From 9ecd2a9cbfcd7ef63d87fb0e3041b8d38bb2b07f Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 31 Aug 2026 16:21:31 +0100 Subject: [PATCH 1/3] nuget updates --- .../StreamManagementTool.csproj | 2 +- ...ionProcessing.MerchantFileProcessor.csproj | 12 +- .../TransactionProcessing.MerchantPos.csproj | 10 +- .../DataGenerator/Program.cs | 289 ----- .../TransactionDataGenerator.csproj | 12 - .../JobTestDriver/JobTestDriver.csproj | 10 - .../JobTestDriver/Program.cs | 12 - .../Extensions.cs | 54 - .../ITransactionDataGeneratorService.cs | 34 - .../IdGenerationService.cs | 46 - .../ProductSubType.cs | 10 - .../RunningMode.cs | 8 - .../TraceEventArgs.cs | 19 - .../TraceHandler.cs | 3 - .../TransactionDataGeneratorService.cs | 1073 ----------------- ...sing.SchedulerService.DataGenerator.csproj | 16 - .../UploadFile.cs | 125 -- ...TransactionProcessing.SchedulerService.sln | 46 - .../TransactionProcessor.HealthChecksUI.sln | 25 - .../Program.cs | 42 - .../Properties/launchSettings.json | 27 - .../Startup.cs | 89 -- ...TransactionProcessor.HealthChecksUI.csproj | 14 - .../appsettings.Development.json | 9 - .../appsettings.json | 37 - ...appsettings.preproduction.development.json | 9 - .../appsettings.preproduction.json | 33 - .../appsettings.staging.json | 37 - .../hosting.json | 3 - ...ransactionProcessor.SystemSetupTool.csproj | 10 +- 30 files changed, 17 insertions(+), 2099 deletions(-) delete mode 100644 TransactionProcessing.SchedulerService/DataGenerator/Program.cs delete mode 100644 TransactionProcessing.SchedulerService/DataGenerator/TransactionDataGenerator.csproj delete mode 100644 TransactionProcessing.SchedulerService/JobTestDriver/JobTestDriver.csproj delete mode 100644 TransactionProcessing.SchedulerService/JobTestDriver/Program.cs delete mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/Extensions.cs delete mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/ITransactionDataGeneratorService.cs delete mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/IdGenerationService.cs delete mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/ProductSubType.cs delete mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/RunningMode.cs delete mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TraceEventArgs.cs delete mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TraceHandler.cs delete mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs delete mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionProcessing.SchedulerService.DataGenerator.csproj delete mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/UploadFile.cs delete mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.sln delete mode 100644 TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI.sln delete mode 100644 TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Program.cs delete mode 100644 TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Properties/launchSettings.json delete mode 100644 TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Startup.cs delete mode 100644 TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI.csproj delete mode 100644 TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.Development.json delete mode 100644 TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.json delete mode 100644 TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.preproduction.development.json delete mode 100644 TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.preproduction.json delete mode 100644 TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.staging.json delete mode 100644 TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/hosting.json diff --git a/StreamManagementTool/StreamManagementTool.csproj b/StreamManagementTool/StreamManagementTool.csproj index e0539e5..09c2616 100644 --- a/StreamManagementTool/StreamManagementTool.csproj +++ b/StreamManagementTool/StreamManagementTool.csproj @@ -8,7 +8,7 @@ - + diff --git a/TransactionProcessing.MerchantFileProcessor/TransactionProcessing.MerchantFileProcessor.csproj b/TransactionProcessing.MerchantFileProcessor/TransactionProcessing.MerchantFileProcessor.csproj index e2822e2..73b8be4 100644 --- a/TransactionProcessing.MerchantFileProcessor/TransactionProcessing.MerchantFileProcessor.csproj +++ b/TransactionProcessing.MerchantFileProcessor/TransactionProcessing.MerchantFileProcessor.csproj @@ -8,16 +8,16 @@ - + - - - - - + + + + + diff --git a/TransactionProcessing.MerchantPos/TransactionProcessing.MerchantPos.csproj b/TransactionProcessing.MerchantPos/TransactionProcessing.MerchantPos.csproj index 2dd4195..ecc1821 100644 --- a/TransactionProcessing.MerchantPos/TransactionProcessing.MerchantPos.csproj +++ b/TransactionProcessing.MerchantPos/TransactionProcessing.MerchantPos.csproj @@ -12,11 +12,11 @@ - - - - - + + + + + diff --git a/TransactionProcessing.SchedulerService/DataGenerator/Program.cs b/TransactionProcessing.SchedulerService/DataGenerator/Program.cs deleted file mode 100644 index 77d386d..0000000 --- a/TransactionProcessing.SchedulerService/DataGenerator/Program.cs +++ /dev/null @@ -1,289 +0,0 @@ -using System; -using Microsoft.Extensions.Logging; -using SimpleResults; -using TransactionProcessing.SchedulerService.DataGenerator; -using TransactionProcessor.DataTransferObjects.Responses.Contract; -using TransactionProcessor.DataTransferObjects.Responses.Merchant; -#nullable enable - -namespace TransactionDataGenerator{ - using System.Collections.Generic; - using System.Linq; - using System.Net.Http; - using System.Threading; - using System.Threading.Tasks; - using SecurityService.Client; - using TransactionProcessor.Client; - - /// - /// - /// - class Program{ - - private static SecurityServiceClient SecurityServiceClient = null!; - - private static TransactionProcessorClient TransactionProcessorClient = null!; - - private static Func baseAddressFunc = null!; - - static async Task Main(string[] args){ - - - HttpClientHandler handler = new HttpClientHandler(); - HttpClient httpClient = new HttpClient(handler); - - baseAddressFunc = (apiName) => { - String ipaddress = "192.168.1.163"; - - if (apiName == "SecurityService"){ - return $"https://{ipaddress}:5001"; - } - - if (apiName == "TransactionProcessorApi") - { - return $"http://{ipaddress}:5002"; - //return $"http://127.0.0.1:5002"; - } - - if (apiName == "FileProcessorApi"){ - return $"http://{ipaddress}:5009"; - } - - if (apiName == "TestHostApi"){ - return $"http://{ipaddress}:9000"; - } - - throw new InvalidOperationException($"Unknown API name: {apiName}"); - }; - Shared.Logger.Logger.Initialise(new ConsoleLogger()); - Program.SecurityServiceClient = new SecurityServiceClient(baseAddressFunc, httpClient); - - Program.TransactionProcessorClient = new TransactionProcessorClient(baseAddressFunc, httpClient); - - // Set an estate - Guid estateId = Guid.Parse("435613ac-a468-47a3-ac4f-649d89764c22"); - - // Get a token to talk to the estate service - CancellationToken cancellationToken = new(); - String clientId = "serviceClient"; - String clientSecret = ResolveRequiredSecret("TRANSACTIONPROCESSOR_SERVICECLIENT_SECRET"); - ITransactionDataGeneratorService g = new TransactionDataGeneratorService(Program.SecurityServiceClient, - Program.TransactionProcessorClient, - Program.baseAddressFunc("TransactionProcessorApi"), - Program.baseAddressFunc("FileProcessorApi"), - Program.baseAddressFunc("TestHostApi"), - clientId, - clientSecret, - RunningMode.Live); - - g.TraceGenerated += arguments => { - Console.WriteLine($"{arguments.TraceLevel}|{arguments.Message}"); - }; - - await Program.GenerateTransactions(g, estateId, cancellationToken); - //await Program.GenerateStatements(g, estateId, cancellationToken); - - Console.WriteLine("Process Complete"); - } - - private static string ResolveRequiredSecret(string environmentVariableName) - { - string? secret = Environment.GetEnvironmentVariable(environmentVariableName); - if (!string.IsNullOrWhiteSpace(secret)) - { - return secret; - } - - throw new InvalidOperationException($"Missing required secret. Set {environmentVariableName}."); - } - - private static async Task GenerateStatements(ITransactionDataGeneratorService g, Guid estateId, CancellationToken cancellationToken){ - Result> getMerchantsResult = await g.GetMerchants(estateId, cancellationToken); - if (getMerchantsResult.IsFailed) - return; - List merchants = getMerchantsResult.Data ?? []; - foreach (MerchantResponse merchant in merchants){ - await g.GenerateMerchantStatement(merchant.EstateId, merchant.MerchantId, DateTime.Now.AddMonths(-2), cancellationToken); - } - } - - private static async Task GenerateTransactions(ITransactionDataGeneratorService g, Guid estateId, CancellationToken cancellationToken){ - // Set the date range - DateTime startDate = new DateTime(2025, 8, 29); //27/7 - DateTime endDate = new DateTime(2025, 9,2); // This is the date of the last generated transaction - - Result> dateRangeResult = g.GenerateDateRange(startDate, endDate); - if (dateRangeResult.IsFailed) - { - Console.WriteLine($"Failed to generate date range: {dateRangeResult.Message}"); - return; - } - var allContractsResult = await g.GetEstateContracts(estateId, cancellationToken); - if (allContractsResult.IsFailed) { - Console.WriteLine($"Failed to get estate contracts: {allContractsResult.Message}"); - } - var merchantsResult = await g.GetMerchants(estateId, cancellationToken); - if (merchantsResult.IsFailed) - { - Console.WriteLine($"Failed to get merchants: {merchantsResult.Message} "); - } - Dictionary<(String, String), Decimal> floatDeposits = new() { - { ("Healthcare Centre 1 Contract", "10 KES Voucher"), 1400 }, - { ("Healthcare Centre 1 Contract", "Custom"), 27000 }, - { ("Safaricom Contract", "100 KES Topup"), 14000 }, - { ("Safaricom Contract", "200 KES Topup"), 28000 }, - { ("Safaricom Contract", "Custom"), 27000 }, - { ("PataPawa PostPay Contract", "Post Pay Bill Pay"), 18000 }, - { ("PataPawa prePay Contract", "Pre Pay Bill Pay"), 18000 } - }; - - DataToSend dataToSend = 0; - // Everything - //dataToSend = DataToSend.FloatDeposits | DataToSend.Logons | DataToSend.Sales | DataToSend.Files | DataToSend.Settlement; - - // Everything (No settlement) - dataToSend = DataToSend.FloatDeposits | DataToSend.Logons | DataToSend.Sales | DataToSend.Files; - - // Floats - //dataToSend = DataToSend.FloatDeposits; - - // Logons and Sales - //dataToSend = DataToSend.Logons | DataToSend.Sales; - - // Files - //dataToSend = DataToSend.Files; - - // Settlement - dataToSend = DataToSend.Settlement; - - if (dataToSend == 0) { - Console.WriteLine("No data to send"); - return; - } - - foreach (DateTime dateTime in dateRangeResult.Data){ - - if ((dataToSend & DataToSend.FloatDeposits) == DataToSend.FloatDeposits) - { - foreach (ContractResponse contractResponse in allContractsResult.Data) { - foreach (ContractProduct contractResponseProduct in contractResponse.Products) { - // Lookup the deposit amount here - KeyValuePair<(String, String), Decimal> depositAmount = floatDeposits.SingleOrDefault(f => - f.Key.Item1 == contractResponse.Description && - f.Key.Item2 == contractResponseProduct.Name); - - await g.MakeFloatDeposit(dateTime, estateId, contractResponse.ContractId, - contractResponseProduct.ProductId, depositAmount.Value, cancellationToken); - } - } - } - - if ((dataToSend & DataToSend.Logons) == DataToSend.Logons) { - foreach (MerchantResponse merchant in merchantsResult.Data) { - - // Send a logon transaction - await g.PerformMerchantLogon(dateTime, merchant, cancellationToken); - } - } - - if ((dataToSend & DataToSend.Sales) == DataToSend.Sales) - { - foreach (MerchantResponse merchant in merchantsResult.Data) { - // Get the merchants contracts - Result> getMerchantContractsResult = await g.GetMerchantContracts(merchant, cancellationToken); - if (getMerchantContractsResult.IsFailed) { - Console.WriteLine($"Failed to get merchant contracts: {getMerchantContractsResult.Message}"); - break; - } - foreach (ContractResponse contract in getMerchantContractsResult.Data) { - // Generate and send some sales - - await g.SendSales(dateTime, merchant, contract, 0,0, cancellationToken); - } - } - } - - if ((dataToSend & DataToSend.Files) == DataToSend.Files) { - foreach (MerchantResponse merchant in merchantsResult.Data) { - // Get the merchants contracts - Result> getMerchantContractsResult = await g.GetMerchantContracts(merchant, cancellationToken); - if (getMerchantContractsResult.IsFailed) - { - Console.WriteLine($"Failed to get merchant contracts: {getMerchantContractsResult.Message}"); - break; - } - foreach (ContractResponse contract in getMerchantContractsResult.Data) { - // Generate a file and upload - await g.SendUploadFile(dateTime, contract, merchant, Guid.Parse("75e19f2e-2ce9-4296-930a-3bb4416375f4"), cancellationToken); - - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); - } - - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); - } - } - - // Settlement - if ((dataToSend & DataToSend.Settlement) == DataToSend.Settlement) { - try { - await g.PerformSettlement(dateTime, estateId, cancellationToken); - - await Task.Delay(TimeSpan.FromSeconds(30), cancellationToken); - } - catch (Exception e) { - Console.WriteLine(e); - } - } - } - } - - [Flags] - enum DataToSend { - FloatDeposits= 1, - Logons = 2, - Sales = 4, - Files = 8, - Settlement = 16 - } - } - - public class ConsoleLogger : Shared.Logger.ILogger { - public void LogCritical(Exception exception) { - Console.WriteLine(exception); - } - - public void LogCritical(String message, - Exception exception) { - Console.WriteLine(message); - Console.WriteLine(exception); - } - - public void LogDebug(String message) { - Console.WriteLine(message); - } - - public void LogError(Exception exception) { - Console.WriteLine(exception); - } - - public void LogError(String message, - Exception exception) { - Console.WriteLine(message); - Console.WriteLine(exception); - } - - public void LogInformation(String message) { - Console.WriteLine(message); - } - - public void LogTrace(String message) { - Console.WriteLine(message); - } - - public void LogWarning(String message) { - Console.WriteLine(message); - } - - public Boolean IsInitialised { get; set; } - } -} diff --git a/TransactionProcessing.SchedulerService/DataGenerator/TransactionDataGenerator.csproj b/TransactionProcessing.SchedulerService/DataGenerator/TransactionDataGenerator.csproj deleted file mode 100644 index ca81c6b..0000000 --- a/TransactionProcessing.SchedulerService/DataGenerator/TransactionDataGenerator.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - Exe - net10.0 - - - - - - - diff --git a/TransactionProcessing.SchedulerService/JobTestDriver/JobTestDriver.csproj b/TransactionProcessing.SchedulerService/JobTestDriver/JobTestDriver.csproj deleted file mode 100644 index dcb47e8..0000000 --- a/TransactionProcessing.SchedulerService/JobTestDriver/JobTestDriver.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - Exe - net10.0 - enable - enable - - - diff --git a/TransactionProcessing.SchedulerService/JobTestDriver/Program.cs b/TransactionProcessing.SchedulerService/JobTestDriver/Program.cs deleted file mode 100644 index 77424bb..0000000 --- a/TransactionProcessing.SchedulerService/JobTestDriver/Program.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Threading.Tasks; - -namespace JobTestDriver -{ - internal class Program - { - static Task Main(string[] args) - { - return Task.CompletedTask; - } - } -} diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/Extensions.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/Extensions.cs deleted file mode 100644 index e1671a3..0000000 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/Extensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Newtonsoft.Json; -using TransactionProcessor.DataTransferObjects; - -namespace TransactionProcessing.SchedulerService.DataGenerator; - -public static class Extensions -{ - #region Methods - - public static Decimal GetAmount(this SaleTransactionRequest request) - { - if (request.AdditionalTransactionMetadata.ContainsKey("Amount")) - { - return Decimal.Parse(request.AdditionalTransactionMetadata["Amount"]); - } - - return 0; - } - - public static SerialisedMessage CreateSerialisedMessage(this LogonTransactionRequest request) - { - SerialisedMessage serialisedMessage = new SerialisedMessage(); - serialisedMessage.Metadata.Add("estate_id", request.EstateId.ToString()); - serialisedMessage.Metadata.Add("merchant_id", request.MerchantId.ToString()); - serialisedMessage.SerialisedData = JsonConvert.SerializeObject(request, - new JsonSerializerSettings - { - TypeNameHandling = TypeNameHandling.All - }); - - return serialisedMessage; - } - - public static SerialisedMessage CreateSerialisedMessage(this SaleTransactionRequest request) - { - SerialisedMessage serialisedMessage = new SerialisedMessage(); - serialisedMessage.Metadata.Add("estate_id", request.EstateId.ToString()); - serialisedMessage.Metadata.Add("merchant_id", request.MerchantId.ToString()); - serialisedMessage.SerialisedData = JsonConvert.SerializeObject(request, - new JsonSerializerSettings - { - TypeNameHandling = TypeNameHandling.All - }); - - return serialisedMessage; - } - - public static T GetSerialisedMessageResponseDTO(this SerialisedMessage serialisedMessage) - { - return JsonConvert.DeserializeObject(serialisedMessage.SerialisedData)!; - } - - #endregion -} diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/ITransactionDataGeneratorService.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/ITransactionDataGeneratorService.cs deleted file mode 100644 index f987d46..0000000 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/ITransactionDataGeneratorService.cs +++ /dev/null @@ -1,34 +0,0 @@ -using SimpleResults; -using System.Text.Json; -using TransactionProcessor.DataTransferObjects; -using TransactionProcessor.DataTransferObjects.Responses.Contract; -using TransactionProcessor.DataTransferObjects.Responses.Merchant; - -namespace TransactionProcessing.SchedulerService.DataGenerator; - -public interface ITransactionDataGeneratorService -{ - #region Methods - - Result> GenerateDateRange(DateTime startDate, DateTime endDate); - - Task>> GetEstateContracts(Guid estateId, CancellationToken cancellationToken); - Task>> GetMerchantContracts(MerchantResponse merchant, CancellationToken cancellationToken); - Task>> GetMerchants(Guid estateId, CancellationToken cancellationToken); - Task> PerformMerchantLogon(DateTime dateTime, MerchantResponse merchant, CancellationToken cancellationToken); - Task PerformSettlement(DateTime dateTime, Guid estateId, CancellationToken cancellationToken); - - Task PerformMerchantSettlement(DateTime dateTime, - Guid estateId, - Guid merchantId, - CancellationToken cancellationToken); - Task SendSales(DateTime dateTime, MerchantResponse merchant, ContractResponse contract, Int32 numberOfSales, Int32 timeDelay, CancellationToken cancellationToken); - Task SendUploadFile(DateTime dateTime, ContractResponse contract, MerchantResponse merchant, Guid userId, CancellationToken cancellationToken); - Task> GetMerchant(Guid estateId, Guid merchantId, CancellationToken cancellationToken); - Task GenerateMerchantStatement(Guid estateId, Guid merchantId, DateTime statementDateTime, CancellationToken cancellationToken); - Task MakeFloatDeposit(DateTime dateTime, Guid estateId, Guid contractId, Guid contractProductId, Decimal amount, CancellationToken cancellationToken); - - event TraceHandler TraceGenerated; - - #endregion -} \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/IdGenerationService.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/IdGenerationService.cs deleted file mode 100644 index 7ecc624..0000000 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/IdGenerationService.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Security.Cryptography; -using System.Text; -using Newtonsoft.Json; -using Shared.Serialisation; - -namespace TransactionProcessing.SchedulerService.DataGenerator; - -[ExcludeFromCodeCoverage] -public class IdGenerationService -{ - internal delegate Guid GenerateUniqueIdFromObject(Object payload); - internal delegate Guid GenerateUniqueIdFromString(String payload); - - - private static readonly JsonSerialiser JsonSerialiser = new(() => new JsonSerializerSettings - { - Formatting = Formatting.None - }); - - private static readonly GenerateUniqueIdFromString GenerateGuidFromString = uniqueKey => { - using SHA256 sha256Hash = SHA256.Create(); - //Generate hash from the key - Byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(uniqueKey)); - - Byte[] j = bytes.Skip(Math.Max(0, bytes.Count() - 16)).ToArray(); //Take last 16 - - //Create our Guid. - return new Guid(j); - }; - - private static readonly GenerateUniqueIdFromObject GenerateUniqueId = - data => - { - string serialised = IdGenerationService.JsonSerialiser.Serialise(data); - return IdGenerationService.GenerateGuidFromString(serialised); - }; - - public static Guid GenerateFloatAggregateId(Guid estateId, Guid contractId, Guid productId) => - IdGenerationService.GenerateUniqueId(new - { - estateId, - contractId, - productId - }); -} diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/ProductSubType.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/ProductSubType.cs deleted file mode 100644 index 1e7983d..0000000 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/ProductSubType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace TransactionProcessing.SchedulerService.DataGenerator; - -public enum ProductSubType -{ - NotSet, - MobileTopup, - Voucher, - BillPaymentPostPay, - BillPaymentPrePay, -} \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/RunningMode.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/RunningMode.cs deleted file mode 100644 index d2fdcdd..0000000 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/RunningMode.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace TransactionProcessing.SchedulerService.DataGenerator; - -public enum RunningMode -{ - WhatIf, - - Live -} \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TraceEventArgs.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TraceEventArgs.cs deleted file mode 100644 index 0da0214..0000000 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TraceEventArgs.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace TransactionProcessing.SchedulerService.DataGenerator; - -public class TraceEventArgs : EventArgs -{ - public enum Level - { - Trace, - Warning, - Error - } - - #region Properties - - public String Message { get; set; } = String.Empty; - - public Level TraceLevel { get; set; } - - #endregion -} diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TraceHandler.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TraceHandler.cs deleted file mode 100644 index 4bd19a9..0000000 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TraceHandler.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace TransactionProcessing.SchedulerService.DataGenerator; - -public delegate void TraceHandler(TraceEventArgs traceArguments); \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs deleted file mode 100644 index 15d8913..0000000 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs +++ /dev/null @@ -1,1073 +0,0 @@ -using Newtonsoft.Json; -using Polly; -using SecurityService.Client; -using SecurityService.DataTransferObjects.Responses; -using Shared.Results; -using SimpleResults; -using System; -using System.Net.Http.Headers; -using System.Security.Cryptography; -using System.Text; -using TransactionProcessor.Client; -using TransactionProcessor.DataTransferObjects; -using TransactionProcessor.DataTransferObjects.Requests.Merchant; -using TransactionProcessor.DataTransferObjects.Responses.Contract; -using TransactionProcessor.DataTransferObjects.Responses.Estate; -using TransactionProcessor.DataTransferObjects.Responses.Merchant; - -namespace TransactionProcessing.SchedulerService.DataGenerator; - -public class TransactionDataGeneratorService : ITransactionDataGeneratorService { - private readonly ISecurityServiceClient SecurityServiceClient; - private readonly ITransactionProcessorClient TransactionProcessorClient; - private readonly String TransactionProcessorApi; - private readonly String FileProcessorApi; - - public TransactionDataGeneratorService(ISecurityServiceClient securityServiceClient, - ITransactionProcessorClient transactionProcessorClient, - String transactionProcessorApi, - String fileProcessorApi, - String testHostApi, - String clientId, - String clientSecret, - RunningMode runningMode = RunningMode.WhatIf) { - this.SecurityServiceClient = securityServiceClient; - this.TransactionProcessorClient = transactionProcessorClient; - this.TransactionProcessorApi = transactionProcessorApi; - this.FileProcessorApi = fileProcessorApi; - this.TestHostApi = testHostApi; - this.ClientId = clientId; - this.ClientSecret = clientSecret; - this.RunningMode = runningMode; - } - - public Result> GenerateDateRange(DateTime startDate, - DateTime endDate) { - this.WriteTrace($"Generating date range between {startDate:dd-MM-yyyy} and {endDate:dd-MM-yyyy}"); - List dateRange = new List(); - - if (endDate.Subtract(startDate).Days == 0) { - dateRange.Add(startDate); - } - else { - while (endDate.Subtract(startDate).Days >= 0) { - dateRange.Add(startDate); - startDate = startDate.AddDays(1); - } - } - - this.WriteTrace($"{dateRange.Count} dates generated"); - - return Result.Success(dateRange); - } - - public async Task>> GetEstateContracts(Guid estateId, - CancellationToken cancellationToken) { - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - - this.WriteTrace($"About to get contracts for Estate Id [{estateId}]"); - Result>? result = await this.TransactionProcessorClient.GetContracts(tokenResult.Data, estateId, cancellationToken); - if (result.IsFailed) { - this.WriteError("Error getting contracts"); - this.WriteError(result.Message); - return result; - } - - this.WriteTrace($"{result.Data.Count} contracts returned for Estate"); - - return result; - } - - public async Task>> GetMerchantContracts(MerchantResponse merchant, - CancellationToken cancellationToken) { - // TODO: not sure if we even need this - if (merchant == null) { - this.WriteError("Merchant is null"); - return Result.Invalid("Merchant is null"); - } - - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - - this.WriteTrace($"About to get contracts for Merchant [{merchant.MerchantId}] Estate Id [{merchant.EstateId}]"); - Result>? result = await this.TransactionProcessorClient.GetMerchantContracts(tokenResult.Data, merchant.EstateId, merchant.MerchantId, cancellationToken); - if (result.IsFailed) { - this.WriteError("Error getting merchant contracts"); - this.WriteError(result.Message); - return result; - } - - this.WriteTrace($"{result.Data.Count} contracts returned for Merchant"); - - return result; - } - - public async Task>> GetMerchants(Guid estateId, - CancellationToken cancellationToken) { - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - this.WriteTrace($"About to get merchants for Estate Id [{estateId}]"); - Result>? result = await this.TransactionProcessorClient.GetMerchants(tokenResult.Data, estateId, cancellationToken); - if (result.IsFailed) { - this.WriteError("Error getting merchants"); - this.WriteError(result.Message); - return result; - } - - this.WriteTrace($"{result.Data.Count} merchants returned for Estate"); - - return result; - } - - public async Task> PerformMerchantLogon(DateTime dateTime, - MerchantResponse merchant, - CancellationToken cancellationToken) { - if (merchant == null) { - this.WriteError("Merchant is null"); - return Result.Invalid("Merchant is null"); - } - - // Build logon message - String deviceIdentifier = merchant.Devices.Single().Value; - LogonTransactionRequest logonTransactionRequest = new LogonTransactionRequest { - DeviceIdentifier = deviceIdentifier, - EstateId = merchant.EstateId, - MerchantId = merchant.MerchantId, - TransactionDateTime = dateTime.Date.AddMinutes(1), - TransactionNumber = "1", - TransactionType = "Logon" - }; - - - this.WriteTrace($"About to send Logon Transaction for Merchant [{merchant.MerchantName}]"); - - Result result = await this.SendLogonTransaction(merchant, logonTransactionRequest, cancellationToken); - if (result.IsFailed) { - this.WriteError("Error getting merchants"); - this.WriteError(result.Message); - return Result.Failure(result.Message); - } - - this.WriteTrace($"Logon Transaction for Merchant [{merchant.MerchantName}] sent"); - return result; - } - - public async Task PerformSettlement(DateTime dateTime, - Guid estateId, - CancellationToken cancellationToken) { - Result> getMerchantsResult = await this.GetMerchants(estateId, cancellationToken); - if (getMerchantsResult.IsFailed) - return Result.Failure("Error getting merchants"); - List? merchants = getMerchantsResult.Data; - List errors = new List(); - foreach (MerchantResponse merchantResponse in merchants) { - this.WriteTrace($"About to send Process Settlement Request for Date [{dateTime:dd-MM-yyyy}] and Estate [{estateId}] and Merchant [{merchantResponse.MerchantId}]"); - Result result = await this.SendProcessSettlementRequest(dateTime, estateId, merchantResponse.MerchantId, cancellationToken); - if (result.IsFailed) { - this.WriteError($"Error sending Process Settlement Request for Date [{dateTime:dd-MM-yyyy}] and Estate [{estateId}]"); - this.WriteError(result.Message); - errors.Add($"Error sending Process Settlement Request for Date [{dateTime:dd-MM-yyyy}] and Estate [{estateId}]"); - } - - this.WriteTrace($"Process Settlement Request sent for Date [{dateTime:dd-MM-yyyy}] and Estate [{estateId}] and Merchant [{merchantResponse.MerchantId}]"); - } - - if (errors.Any()) { - return Result.Failure(String.Join(",", errors)); - } - return Result.Success(); - } - - public async Task PerformMerchantSettlement(DateTime dateTime, - Guid estateId, - Guid merchantId, - CancellationToken cancellationToken) { - this.WriteTrace($"About to send Process Settlement Request for Date [{dateTime:dd-MM-yyyy}] and Estate [{estateId}] and Merchant [{merchantId}]"); - Result result = await this.SendProcessSettlementRequest(dateTime, estateId, merchantId, cancellationToken); - if (result.IsFailed) { - this.WriteError($"Error sending Process Settlement Request for Date [{dateTime:dd-MM-yyyy}] and Estate [{estateId}] and MerchantId [{merchantId}]"); - this.WriteError(result.Message); - return Result.Failure($"Error sending Process Settlement Request for Date [{dateTime:dd-MM-yyyy}] and Estate [{estateId}] and MerchantId [{merchantId}]"); - } - - this.WriteTrace($"Process Settlement Request sent for Date [{dateTime:dd-MM-yyyy}] and Estate [{estateId}] and Merchant [{merchantId}]"); - - return Result.Success(); - } - - public async Task SendSales(DateTime dateTime, - MerchantResponse merchant, - ContractResponse contract, - Int32 numberOfSales, - Int32 timeDelay, - CancellationToken cancellationToken) { - List salesToSend = new List(); - Decimal depositAmount = 0; - (Int32 accountNumber, String accountName, Decimal balance) billDetails = default; - (Int32 meterNumber, String customerName, Decimal amount) meterDetails = default; - - // Step 2: Decide how many total transactions to generate in this run - numberOfSales = RandomNumberGenerator.GetInt32(1, 6); // e.g. 1–5 transactions per run - List<(SaleTransactionRequest request, Decimal amount)> saleRequests = []; - for (int i = 0; i < numberOfSales; i++) { - ContractProduct? contractProduct = contract.Products[RandomNumberGenerator.GetInt32(contract.Products.Count)]; - - // Spread transactions randomly across 5 minutes - int delayMs = RandomNumberGenerator.GetInt32(0, timeDelay * 60 * 1000); - - await Task.Delay(delayMs); - ProductSubType productSubType = this.GetProductSubType(contract.OperatorName); - - if (productSubType == ProductSubType.BillPaymentPostPay) { - // Create a bill for this sale - billDetails = await this.CreateBillPaymentBill(contract.OperatorName, contractProduct, cancellationToken); - } - - if (productSubType == ProductSubType.BillPaymentPrePay) { - // Create a meter - meterDetails = await this.CreateBillPaymentMeter(contract.OperatorName, contractProduct, cancellationToken); - } - - saleRequests = productSubType switch { - ProductSubType.MobileTopup => this.BuildMobileTopupSaleRequests(dateTime, merchant, contract, contractProduct), - ProductSubType.Voucher => this.BuildVoucherSaleRequests(dateTime, merchant, contract, contractProduct), - ProductSubType.BillPaymentPostPay => this.BuildPataPawaPostPayBillPaymentSaleRequests(dateTime, merchant, contract, contractProduct, billDetails), - ProductSubType.BillPaymentPrePay => this.BuildPataPawaPrePayBillPaymentSaleRequests(dateTime, merchant, contract, contractProduct, meterDetails), - _ => throw new InvalidOperationException($"Product Sub Type [{productSubType}] not yet supported") - }; - - // Add the value of the sale to the deposit amount - Boolean addToDeposit = i switch { - _ when i == numberOfSales => false, - _ => true - }; - - if (addToDeposit) { - depositAmount += saleRequests.Sum(sr => sr.amount); - } - - salesToSend.AddRange(saleRequests.Select(s => s.request)); - - } - - // Build up a deposit (minus the last sale amount) - if (depositAmount > 0) { - MakeMerchantDepositRequest depositRequest = this.CreateMerchantDepositRequest(depositAmount, dateTime); - - // Send the deposit - Result result = await this.SendMerchantDepositRequest(merchant, depositRequest, cancellationToken); - - if (result.IsFailed) { - return result; - } - } - - Int32 salesSent = 0; - IOrderedEnumerable orderedSales = salesToSend.OrderBy(s => s.TransactionDateTime); - // Send the sales to the host - foreach (SaleTransactionRequest sale in orderedSales) { - sale.TransactionNumber = this.GetTransactionNumber().ToString(); - Result saleResult = await this.SendSaleTransaction(merchant, sale, cancellationToken); - if (saleResult.IsSuccess) { - salesSent++; - } - } - - if (salesSent == 0) { - // All sales failed - return Result.Failure("All sales have failed"); - } - - this.WriteTraceX($"{salesSent} sales for merchant {merchant.MerchantName} sent to host {orderedSales.Count() - salesSent} sales failed to send"); - return Result.Success(); - } - - public async Task SendUploadFile(DateTime dateTime, - ContractResponse contract, - MerchantResponse merchant, - Guid userId, - CancellationToken cancellationToken) { - Int32 numberOfSales = RandomNumberGenerator.GetInt32(5, 15); - var builtFileResult = await this.BuildUploadFile(dateTime, merchant, contract, numberOfSales, cancellationToken); - - if (builtFileResult.IsFailed) { - return ResultHelpers.CreateFailure(builtFileResult); - } - - Decimal fileValue = builtFileResult.Data.Item1; - UploadFile uploadFile = builtFileResult.Data.Item2; - - if (this.RunningMode == RunningMode.WhatIf) { - this.WriteTrace($"Send File for Merchant [{merchant.MerchantName}] Contract [{contract.OperatorName}] Lines [{uploadFile.GetNumberOfLines()}]"); - return Result.Success(); - } - - // Build up a deposit (minus the last sale amount) - MakeMerchantDepositRequest depositRequest = this.CreateMerchantDepositRequest(fileValue, dateTime); - - // Send the deposit - var result = await this.SendMerchantDepositRequest(merchant, depositRequest, cancellationToken); - - if (result.IsFailed) - { - return result; - } - - Result fileSendResult = await this.UploadFile(uploadFile, uploadFile.UserId, dateTime, cancellationToken); - - if (fileSendResult.IsFailed) - { - return fileSendResult; - } - - return Result.Success(); - } - - private async Task UploadFile(UploadFile uploadFile, Guid userId, DateTime fileDateTime, CancellationToken cancellationToken) - { - var formData = new MultipartFormDataContent(); - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - - var fileContent = new ByteArrayContent(uploadFile.GetFileContents()); - fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data"); - formData.Add(fileContent, "file", $"bulkfile{fileDateTime:yyyy-MM-dd}"); - formData.Add(new StringContent(uploadFile.EstateId.ToString()), "request.EstateId"); - formData.Add(new StringContent(uploadFile.MerchantId.ToString()), "request.MerchantId"); - formData.Add(new StringContent(uploadFile.FileProfileId.ToString()), "request.FileProfileId"); - formData.Add(new StringContent(userId.ToString()), "request.UserId"); - formData.Add(new StringContent(fileDateTime.ToString("yyyy-MM-dd HH:mm:ss")), "request.UploadDateTime"); - - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"{this.FileProcessorApi}/api/files") - { - Content = formData, - }; - - request.Headers.Authorization = new AuthenticationHeaderValue("bearer", tokenResult.Data); - try - { - - this.WriteTrace($"About to upload file for Merchant [{uploadFile.MerchantId}]"); - using (HttpClient client = new HttpClient()) - { - await client.SendAsync(request, cancellationToken); - } - this.WriteTrace($"File uploaded for Merchant [{uploadFile.MerchantId}]"); - return Result.Success(); - } - catch (Exception ex) - { - this.WriteError($"Error uploading file for merchant [{uploadFile.MerchantId}]"); - this.WriteError(ex); - return Result.Failure(ex.Message); - } - } - - private static async Task GetFileProfileIdFromOperator(String operatorName, CancellationToken cancellationToken) - { - // TODO: get this profile list from API - - switch (operatorName) - { - case "Safaricom": - return Guid.Parse("B2A59ABF-293D-4A6B-B81B-7007503C3476"); - case "Voucher": - return Guid.Parse("8806EDBC-3ED6-406B-9E5F-A9078356BE99"); - default: - return Guid.Empty; - } - } - - private async Task> BuildUploadFile(DateTime dateTime, MerchantResponse merchant, ContractResponse contract, Int32 numberOfLines, CancellationToken cancellationToken) - { - ProductType productType = this.GetProductType(contract.OperatorName); - Guid fileProfileId = await TransactionDataGeneratorService.GetFileProfileIdFromOperator(contract.OperatorName, cancellationToken); - Guid variableProductId = contract.Products.Single(p => p.Value == null).ProductId; - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - - var getEstate = await this.TransactionProcessorClient.GetEstate(tokenResult.Data, merchant.EstateId, cancellationToken); - if (getEstate.IsFailed) - return Result.Failure("Get Estate failed"); - var estate = getEstate.Data; - Guid userId = estate.SecurityUsers.First().SecurityUserId; - Decimal depositAmount = 0; - if (productType == ProductType.MobileTopup) - { - MobileTopupUploadFile mobileTopupUploadFile = new MobileTopupUploadFile(contract.EstateId, merchant.MerchantId, contract.ContractId, variableProductId, fileProfileId, userId); - mobileTopupUploadFile.AddHeader(dateTime); - - for (Int32 i = 1; i <= numberOfLines; i++) - { - Decimal amount = GetAmount(); - String mobileNumber = String.Format($"077777777{i.ToString().PadLeft(2, '0')}"); - mobileTopupUploadFile.AddLine(amount, mobileNumber); - - // Add the value of the sale to the deposit amount - Boolean addToDeposit = i switch - { - _ when i == numberOfLines => false, - _ => true - }; - - if (addToDeposit) - { - depositAmount += amount; - } - } - - mobileTopupUploadFile.AddTrailer(); - return Result.Success<(Decimal, UploadFile)>((depositAmount, mobileTopupUploadFile)); - } - - if (productType == ProductType.Voucher) - { - VoucherTopupUploadFile voucherTopupUploadFile = new VoucherTopupUploadFile(contract.EstateId, merchant.MerchantId, contract.ContractId, variableProductId, fileProfileId, userId); - voucherTopupUploadFile.AddHeader(dateTime); - - for (Int32 i = 1; i <= numberOfLines; i++) - { - Decimal amount = GetAmount(); - String mobileNumber = String.Format($"077777777{i.ToString().PadLeft(2, '0')}"); - String emailAddress = String.Format($"testrecipient{i.ToString().PadLeft(2, '0')}@testing.com"); - String recipient = mobileNumber; - if (i % 2 == 0) - { - recipient = emailAddress; - } - - voucherTopupUploadFile.AddLine(amount, recipient, contract.Description.Replace("Contract", "")); - - // Add the value of the sale to the deposit amount - Boolean addToDeposit = i switch - { - _ when i == numberOfLines => false, - _ => true - }; - - if (addToDeposit) - { - depositAmount += amount; - } - } - - - - voucherTopupUploadFile.AddTrailer(); - return Result.Success<(Decimal, UploadFile)>((depositAmount, voucherTopupUploadFile)); - } - - // Not supported product type for file upload - return Result.Invalid($"Product Type {productType} not supported"); - } - - - private String TestHostApi; - - public static Decimal GetAmount(ContractProduct? product = null) - { - return product switch - { - null => RandomNumberGenerator.GetInt32(9, 250), - _ when product.Value.HasValue == false => RandomNumberGenerator.GetInt32(9, 250), - _ => product.Value.Value - }; - } - - private async Task<(Int32 accountNumber, String accountName, Decimal balance)> CreateBillPaymentBill(String contractOperatorName, ContractProduct contractProduct, CancellationToken cancellationToken) - { - if (contractOperatorName == "PataPawa PostPay") - { - Int32 accountNumber = RandomNumberGenerator.GetInt32(1, 100000); - Decimal amount = GetAmount(contractProduct); - - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"{this.TestHostApi}/api/developer/patapawapostpay/createbill"); - var body = new - { - due_date = DateTime.Now.AddDays(1), - amount = amount, - account_number = accountNumber, - account_name = "Test Account 1" - }; - request.Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); - - if (this.RunningMode == RunningMode.WhatIf) - { - this.WriteTrace($"Bill Created Account [{body.account_number}] Balance [{body.amount}]"); - return (body.account_number, body.account_name, body.amount); - } - - using (HttpClient client = new HttpClient()) - { - await client.SendAsync(request, cancellationToken); - } - - return (body.account_number, body.account_name, body.amount); - } - - return default; - } - - private async Task<(Int32 meterNumber, String CustomerName, Decimal balance)> CreateBillPaymentMeter(String contractOperatorName, ContractProduct contractProduct, CancellationToken cancellationToken) - { - if (contractOperatorName == "PataPawa PrePay") - { - Int32 meterNumber = RandomNumberGenerator.GetInt32(1, 100000); - Decimal amount = GetAmount(contractProduct); - - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"{this.TestHostApi}/api/developer/patapawaprepay/createmeter"); - var body = new - { - due_date = DateTime.Now.AddDays(1), - meter_number = meterNumber, - customer_name = $"Customer {meterNumber}" - }; - request.Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); - - if (this.RunningMode == RunningMode.WhatIf) - { - this.WriteTrace($"Meter Created Customer [{body.customer_name}] Meter # [{body.meter_number}]"); - return (body.meter_number, body.customer_name, amount); - } - - using (HttpClient client = new HttpClient()) - { - await client.SendAsync(request, cancellationToken); - } - - return (body.meter_number, body.customer_name, amount); - } - - return default; - } - - private Int32 TransactionNumber; - private Int32 GetTransactionNumber() - { - this.TransactionNumber++; - return this.TransactionNumber; - } - - private async Task SendMerchantDepositRequest(MerchantResponse merchant, - MakeMerchantDepositRequest request, - CancellationToken cancellationToken) { - if (this.RunningMode == RunningMode.WhatIf) { - this.WriteTrace($"Make Deposit [{request.Amount}] for Merchant [{merchant.MerchantName}]"); - return Result.Success(); - } - - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - - this.WriteTrace($"About to make Deposit [{request.Amount}] for Merchant [{merchant.MerchantName}]"); - Result result = await this.TransactionProcessorClient.MakeMerchantDeposit(tokenResult.Data, merchant.EstateId, merchant.MerchantId, request, cancellationToken); - if (result.IsFailed) { - this.WriteError($"Error making merchant deposit for merchant [{merchant.MerchantName}]"); - this.WriteError(result.Message); - return result; - } - - this.WriteTrace($"Deposit [{request.Amount}] made for Merchant [{merchant.MerchantName}]"); - return Result.Success(); - } - - private MakeMerchantDepositRequest CreateMerchantDepositRequest(Decimal depositAmount, DateTime dateTime) - { - // TODO: generate a reference - - MakeMerchantDepositRequest request = new MakeMerchantDepositRequest - { - Amount = depositAmount, - DepositDateTime = dateTime, - Reference = "ABC" - }; - return request; - } - - private async Task SendProcessSettlementRequest(DateTime dateTime, Guid estateId, Guid merchantId, CancellationToken cancellationToken) - { - if (this.RunningMode == RunningMode.WhatIf) - { - this.WriteTrace($"Sending Settlement for Date [{dateTime.Date}] Estate [{estateId}]"); - return Result.Success(); - } - - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - - // Create a retry policy - IAsyncPolicy policy = PolicyFactory.CreatePolicy(2, retryDelay: TimeSpan.FromSeconds(5), policyTag: "TestPolicy", null, ShouldRetryException); - - Result result = await PolicyFactory.ExecuteWithPolicyAsync(async () => - await this.TransactionProcessorClient.ProcessSettlement(tokenResult.Data, dateTime, estateId, merchantId, cancellationToken), - policy, "TransactionDataGeneratorService - SendProcessSettlementRequest"); - return result; - } - - private static bool ShouldRetryException(Exception exception) - { - return exception switch - { - TaskCanceledException { InnerException: TimeoutException } => true, - _ => false - }; - } - - public async Task> GetMerchant(Guid estateId, - Guid merchantId, - CancellationToken cancellationToken) { - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - this.WriteTrace($"About to get merchant {merchantId} for Estate Id [{estateId}]"); - Result? result = await this.TransactionProcessorClient.GetMerchant(tokenResult.Data, estateId, merchantId, cancellationToken); - if (result.IsFailed) { - this.WriteError("Error getting merchant"); - this.WriteError(result.Message); - return result; - } - - this.WriteTrace("Merchant retrieved successfully"); - - return result; - } - - public async Task GenerateMerchantStatement(Guid estateId, - Guid merchantId, - DateTime statementDateTime, - CancellationToken cancellationToken) { - try - { - this.WriteTrace($"About to send Generate Merchant Statement Request for Estate [{estateId}] and Merchant [{merchantId}] StatementDate [{statementDateTime:dd-MM-yyyy}]"); - - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"{this.TransactionProcessorApi}/api/estates/{estateId}/merchants/{merchantId}/statements"); - var body = new - { - merchant_statement_date = statementDateTime, - }; - request.Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); - - if (this.RunningMode == RunningMode.WhatIf) - { - this.WriteTrace($"Merchant Statement Generated for merchant [{merchantId}] Statement Date [{body.merchant_statement_date}]"); - } - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenResult.Data); - - using (HttpClient client = new HttpClient()) - { - await client.SendAsync(request, cancellationToken); - } - - this.WriteTrace($"Generate Merchant Statement Request sent for Estate [{estateId}] and Merchant [{merchantId}] StatementDate [{statementDateTime:dd-MM-yyyy}]"); - return Result.Success(); - - } - catch (Exception ex) - { - this.WriteError($"Error sending Generate Merchant Statement Request for Date [{statementDateTime:dd-MM-yyyy}] and Estate [{estateId}] and Merchant [{merchantId}]"); - this.WriteError(ex); - return Result.Failure(ex.Message); - } - } - - public async Task MakeFloatDeposit(DateTime dateTime, - Guid estateId, - Guid contractId, - Guid contractProductId, - Decimal amount, - CancellationToken cancellationToken) { - Guid floatId = IdGenerationService.GenerateFloatAggregateId(estateId, contractId, contractProductId); - - Decimal costPrice = amount * 0.85m; - - RecordFloatCreditPurchaseRequest request = new RecordFloatCreditPurchaseRequest { FloatId = floatId, CreditAmount = amount, CostPrice = costPrice, PurchaseDateTime = dateTime }; - - return await this.SendFloatDepositRequest(estateId, request, cancellationToken); - } - - private async Task SendFloatDepositRequest(Guid estateId, - RecordFloatCreditPurchaseRequest request, - CancellationToken cancellationToken) { - if (this.RunningMode == RunningMode.WhatIf) { - this.WriteTrace($"Send Float Credit Request for {request.CreditAmount}"); - return Result.Success(); - } - - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - this.WriteTrace("About to Float Credit Request"); - Result? result = await this.TransactionProcessorClient.RecordFloatCreditPurchase(tokenResult.Data, estateId, request, cancellationToken); - if (result.IsFailed) { - this.WriteError("Error Float Credit Request"); - this.WriteError(result.Message); - return result; - } - - this.WriteTrace("Float Credit Request sent"); - - return Result.Success(); - } - - private async Task> SendLogonTransaction(MerchantResponse merchant, - LogonTransactionRequest request, - CancellationToken cancellationToken) { - if (this.RunningMode == RunningMode.WhatIf) { - this.WriteTrace($"Send Logon Transaction for Merchant [{merchant.MerchantName}]"); - return Result.Success(); - } - - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - SerialisedMessage requestSerialisedMessage = request.CreateSerialisedMessage(); - - return await this.TransactionProcessorClient.PerformTransaction(tokenResult.Data, requestSerialisedMessage, CancellationToken.None); - } - - private async Task> SendSaleTransaction(MerchantResponse merchant, - SaleTransactionRequest request, - CancellationToken cancellationToken) { - if (this.RunningMode == RunningMode.WhatIf) { - this.WriteTrace($"Send Sale for Merchant [{merchant.MerchantName}] - {request.TransactionDateTime:yyyy-MM-dd HH:mm:ss} {request.TransactionNumber} - {request.OperatorId} - {request.GetAmount()}"); - return Result.Success(); - } - - Result tokenResult = await this.GetAuthToken(cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - - SerialisedMessage requestSerialisedMessage = request.CreateSerialisedMessage(); - this.WriteTrace($"About to Send sale for Merchant [{merchant.MerchantName}]"); - Result result = new Result(); - for (int i = 0; i < 3; i++) { - try { - result = await this.TransactionProcessorClient.PerformTransaction(tokenResult.Data, requestSerialisedMessage, CancellationToken.None); - break; - } - catch (TaskCanceledException e) { - this.WriteError(e.Message); - } - } - - if (result.IsFailed) - return result; - - this.WriteTrace($"Sale Transaction for Merchant [{merchant.MerchantName}] sent"); - - return result; - } - - public event TraceHandler? TraceGenerated; - private TokenResponse? TokenResponse; - private readonly RunningMode RunningMode; - private readonly String ClientId; - - private readonly String ClientSecret; - - private async Task> GetAuthToken(CancellationToken cancellationToken) { - this.WriteTrace("About to get auth token"); - - TokenResponse? tokenResponse = this.TokenResponse; - if (tokenResponse == null) { - this.WriteTrace("TokenResponse was null"); - Result tokenResult = await this.SecurityServiceClient.GetToken(this.ClientId, this.ClientSecret, cancellationToken); - - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - tokenResponse = tokenResult.Data; - this.TokenResponse = tokenResponse; - } - - if (tokenResponse.Expires.UtcDateTime.Subtract(DateTime.UtcNow) < TimeSpan.FromMinutes(2)) { - this.WriteTrace("TokenResponse was expired"); - Result tokenResult = await this.SecurityServiceClient.GetToken(this.ClientId, this.ClientSecret, cancellationToken); - if (tokenResult.IsFailed) - return ResultHelpers.CreateFailure(tokenResult); - tokenResponse = tokenResult.Data; - this.TokenResponse = tokenResponse; - } - - this.WriteTrace("Auth token retrieved"); - - return Result.Success(tokenResponse.AccessToken); - } - - private void WriteMessage(String message, - TraceEventArgs.Level traceLevel) { - if (this.TraceGenerated != null) { - TraceEventArgs args = new() { TraceLevel = traceLevel, Message = message }; - - this.TraceGenerated.Invoke(args); - } - } - - private void WriteMessageX(String message, - TraceEventArgs.Level traceLevel) - { - if (this.TraceGenerated != null) - { - TraceEventArgs args = new() { TraceLevel = traceLevel, Message = message }; - - this.TraceGenerated.Invoke(args); - } - } - - private void WriteTrace(String message) => this.WriteMessage(message, TraceEventArgs.Level.Trace); - private void WriteTraceX(String message) => this.WriteMessageX(message, TraceEventArgs.Level.Trace); - private void WriteWarning(String message) => this.WriteMessage(message, TraceEventArgs.Level.Warning); - private void WriteError(String message) => this.WriteMessage(message, TraceEventArgs.Level.Error); - private void WriteError(Exception ex) => this.WriteMessage(ex.ToString(), TraceEventArgs.Level.Error); - - private List<(SaleTransactionRequest request, Decimal amount)> BuildVoucherSaleRequests(DateTime dateTime, MerchantResponse merchant, ContractResponse contract, ContractProduct contractProduct) - { - Decimal amount = GetAmount(contractProduct); - - Dictionary requestMetaData = new Dictionary{ - { "Amount", amount.ToString() }, - { "RecipientMobile", "1234567890" } - }; - - List<(SaleTransactionRequest request, Decimal amount)> requests = new List<(SaleTransactionRequest request, Decimal amount)>(); - - String deviceIdentifier = merchant.Devices.Single().Value; - - SaleTransactionRequest request = new SaleTransactionRequest - { - AdditionalTransactionMetadata = requestMetaData, - ContractId = contract.ContractId, - CustomerEmailAddress = String.Empty, - DeviceIdentifier = deviceIdentifier, - MerchantId = merchant.MerchantId, - EstateId = merchant.EstateId, - TransactionType = "Sale", - TransactionDateTime = GetTransactionDateTime(dateTime), - OperatorId = contract.OperatorId, - ProductId = contractProduct.ProductId - }; - requests.Add((request, amount)); - - return requests; - } - - public static DateTime GetTransactionDateTime(DateTime dateTime) - { - - if (dateTime.Hour != 0) - { - // Already have a time only change the seconds - Int32 seconds = RandomNumberGenerator.GetInt32(0, 59); - return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, seconds); - } - else - { - // Generate the time - Int32 hours = RandomNumberGenerator.GetInt32(9, 22); - Int32 minutes = RandomNumberGenerator.GetInt32(0, 59); - Int32 seconds = RandomNumberGenerator.GetInt32(0, 59); - - return dateTime.AddHours(hours).AddMinutes(minutes).AddSeconds(seconds); - } - } - - private List<(SaleTransactionRequest request, Decimal amount)> BuildMobileTopupSaleRequests(DateTime dateTime, MerchantResponse merchant, ContractResponse contract, ContractProduct contractProduct) - { - Decimal amount = GetAmount(contractProduct); - - Dictionary requestMetaData = new Dictionary{ - { "Amount", amount.ToString() }, - { "CustomerAccountNumber", "1234567890" } - }; - - List<(SaleTransactionRequest request, Decimal amount)> requests = new List<(SaleTransactionRequest request, Decimal amount)>(); - - String deviceIdentifier = merchant.Devices.Single().Value; - - SaleTransactionRequest request = new SaleTransactionRequest - { - AdditionalTransactionMetadata = requestMetaData, - ContractId = contract.ContractId, - CustomerEmailAddress = String.Empty, - DeviceIdentifier = deviceIdentifier, - MerchantId = merchant.MerchantId, - EstateId = merchant.EstateId, - TransactionType = "Sale", - TransactionDateTime = GetTransactionDateTime(dateTime), - OperatorId = contract.OperatorId, - ProductId = contractProduct.ProductId - }; - requests.Add((request, amount)); - - return requests; - } - - private List<(SaleTransactionRequest request, Decimal amount)> BuildPataPawaPostPayBillPaymentSaleRequests(DateTime dateTime, MerchantResponse merchant, ContractResponse contract, ContractProduct product, (Int32 accountNumber, String accountName, Decimal balance) billDetails) - { - List<(SaleTransactionRequest request, Decimal amount)> requests = new List<(SaleTransactionRequest request, Decimal amount)>(); - - // Create the requests required - String deviceIdentifier = merchant.Devices.Single().Value; - - // First request is Get Account - Dictionary getAccountRequestMetaData = new Dictionary{ - { "CustomerAccountNumber", billDetails.accountNumber.ToString() }, - { "PataPawaPostPaidMessageType", "VerifyAccount" } - }; - - DateTime transactionDateTime = GetTransactionDateTime(dateTime); - - SaleTransactionRequest getAccountRequest = new SaleTransactionRequest - { - AdditionalTransactionMetadata = getAccountRequestMetaData, - ContractId = contract.ContractId, - CustomerEmailAddress = String.Empty, - DeviceIdentifier = deviceIdentifier, - MerchantId = merchant.MerchantId, - EstateId = merchant.EstateId, - TransactionType = "Sale", - TransactionDateTime = transactionDateTime, - OperatorId = contract.OperatorId, - ProductId = product.ProductId - }; - - requests.Add((getAccountRequest, 0)); - - // Second request is Make Payment - Dictionary makePaymentRequestMetaData = new Dictionary{ - { "CustomerAccountNumber", billDetails.accountNumber.ToString() }, - { "CustomerName", billDetails.accountName }, - { "MobileNumber", "1234567890" }, - { "Amount", billDetails.balance.ToString() }, - { "PataPawaPostPaidMessageType", "ProcessBill" } - }; - - SaleTransactionRequest makePaymentRequest = new SaleTransactionRequest - { - AdditionalTransactionMetadata = makePaymentRequestMetaData, - ContractId = contract.ContractId, - CustomerEmailAddress = String.Empty, - DeviceIdentifier = deviceIdentifier, - MerchantId = merchant.MerchantId, - EstateId = merchant.EstateId, - TransactionType = "Sale", - TransactionDateTime = transactionDateTime.AddSeconds(30), - OperatorId = contract.OperatorId, - ProductId = product.ProductId - }; - - requests.Add((makePaymentRequest, billDetails.balance)); - - return requests; - } - - private List<(SaleTransactionRequest request, Decimal amount)> BuildPataPawaPrePayBillPaymentSaleRequests(DateTime dateTime, MerchantResponse merchant, ContractResponse contract, ContractProduct product, (Int32 meterNumber, String CustomerName, Decimal amount) meterDetails) - { - List<(SaleTransactionRequest request, Decimal amount)> requests = new List<(SaleTransactionRequest request, Decimal amount)>(); - - // Create the requests required - String deviceIdentifier = merchant.Devices.Single().Value; - - // First request is Get Account - Dictionary getAccountRequestMetaData = new Dictionary{ - { "MeterNumber", meterDetails.meterNumber.ToString() }, - { "PataPawaPrePayMessageType", "meter" } - }; - - DateTime transactionDateTime = GetTransactionDateTime(dateTime); - - SaleTransactionRequest getAccountRequest = new SaleTransactionRequest - { - AdditionalTransactionMetadata = getAccountRequestMetaData, - ContractId = contract.ContractId, - CustomerEmailAddress = String.Empty, - DeviceIdentifier = deviceIdentifier, - MerchantId = merchant.MerchantId, - EstateId = merchant.EstateId, - TransactionType = "Sale", - TransactionDateTime = transactionDateTime, - OperatorId = contract.OperatorId, - ProductId = product.ProductId - }; - - requests.Add((getAccountRequest, 0)); - - // Second request is Make Payment - Dictionary makePaymentRequestMetaData = new Dictionary{ - { "MeterNumber", meterDetails.meterNumber.ToString() }, - { "CustomerName", meterDetails.CustomerName }, - { "Amount", meterDetails.amount.ToString() }, - { "PataPawaPrePayMessageType", "vend" } - }; - - SaleTransactionRequest makePaymentRequest = new SaleTransactionRequest - { - AdditionalTransactionMetadata = makePaymentRequestMetaData, - ContractId = contract.ContractId, - CustomerEmailAddress = String.Empty, - DeviceIdentifier = deviceIdentifier, - MerchantId = merchant.MerchantId, - EstateId = merchant.EstateId, - TransactionType = "Sale", - TransactionDateTime = transactionDateTime.AddSeconds(30), - OperatorId = contract.OperatorId, - ProductId = product.ProductId - }; - - requests.Add((makePaymentRequest, meterDetails.amount)); - - return requests; - } - - private ProductType GetProductType(String operatorName) - { - ProductType productType = ProductType.NotSet; - switch (operatorName) - { - case "Safaricom": - productType = ProductType.MobileTopup; - break; - case "Voucher": - productType = ProductType.Voucher; - break; - case "PataPawa PostPay": - case "PataPawa PrePay": - productType = ProductType.BillPayment; - break; - } - - return productType; - } - - private ProductSubType GetProductSubType(String operatorName) - { - ProductSubType productType = ProductSubType.NotSet; - switch (operatorName) - { - case "Safaricom": - productType = ProductSubType.MobileTopup; - break; - case "Voucher": - productType = ProductSubType.Voucher; - break; - case "PataPawa PostPay": - productType = ProductSubType.BillPaymentPostPay; - break; - case "PataPawa PrePay": - productType = ProductSubType.BillPaymentPrePay; - break; - } - - return productType; - } -} diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionProcessing.SchedulerService.DataGenerator.csproj b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionProcessing.SchedulerService.DataGenerator.csproj deleted file mode 100644 index 5911339..0000000 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionProcessing.SchedulerService.DataGenerator.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - net10.0 - enable - enable - - - - - - - - - - diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/UploadFile.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/UploadFile.cs deleted file mode 100644 index 0c2f0cb..0000000 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/UploadFile.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System.Text; - -namespace TransactionProcessing.SchedulerService.DataGenerator; - -public abstract class UploadFile -{ - #region Fields - - protected Int32 FileLineCount; - - protected List FileLines; - - protected Decimal TotalValue; - - #endregion - - #region Constructors - - protected UploadFile(Guid estateId, Guid merchantId, Guid contractId, Guid productId, Guid fileProfileId, Guid userId) - { - this.UserId = userId; - this.FileLines = new List(); - this.EstateId = estateId; - this.MerchantId = merchantId; - this.ContractId = contractId; - this.ProductId = productId; - this.FileProfileId = fileProfileId; - } - - #endregion - - #region Properties - - public Guid EstateId { get; protected set; } - public Guid ContractId { get; protected set; } - public Guid ProductId { get; protected set; } - public Guid FileProfileId { get; protected set; } - public Guid MerchantId { get; protected set; } - public Decimal TotalAmount { get; protected set; } - public Guid UserId { get; protected set; } - - #endregion - - #region Methods - - public void AddHeader(DateTime dateTime) - { - this.FileLines.Add($"H,{dateTime:yyyy-MM-dd-HH-mm-ss}"); - } - - public void AddTrailer() - { - this.FileLines.Add($"T,{this.FileLineCount}"); - } - - public Byte[] GetFileContents() - { - StringBuilder fileData = new StringBuilder(); - String? header = this.FileLines.SingleOrDefault(f => f.StartsWith("H")); - fileData.Append(header); - - List detailLines = this.FileLines.Where(f => f.StartsWith("D")).ToList(); - foreach (String detailLine in detailLines) - { - fileData.AppendLine(detailLine); - } - String? trailer = this.FileLines.SingleOrDefault(f => f.StartsWith("T")); - fileData.Append(trailer); - - return Encoding.UTF8.GetBytes(fileData.ToString()); - } - - public Int32 GetNumberOfLines() - { - return this.FileLines.Count; - } - - #endregion -} - -public class VoucherTopupUploadFile : UploadFile -{ - #region Constructors - - public VoucherTopupUploadFile(Guid estateId, Guid merchantId, Guid contractId, Guid productId, Guid fileProfileId, Guid userId) : base(estateId, merchantId, contractId, productId, fileProfileId, userId) - { - } - - #endregion - - #region Methods - - public void AddLine(Decimal amount, String recipient, String issuerName) - { - this.TotalValue += amount; - this.FileLines.Add($"D,{issuerName},{recipient},{amount}"); - this.FileLineCount++; - this.TotalAmount += amount; - } - - #endregion -} - -public class MobileTopupUploadFile : UploadFile -{ - #region Constructors - - public MobileTopupUploadFile(Guid estateId, Guid merchantId, Guid contractId, Guid productId, Guid fileProfileId, Guid userId) : base(estateId, merchantId, contractId, productId, fileProfileId, userId) - { - } - - #endregion - - #region Methods - - public void AddLine(Decimal amount, String mobileNumber) - { - this.TotalValue += amount; - this.FileLines.Add($"D,{mobileNumber},{amount}"); - this.FileLineCount++; - this.TotalAmount += amount; - } - - #endregion -} \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.sln b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.sln deleted file mode 100644 index cdb659b..0000000 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.sln +++ /dev/null @@ -1,46 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 18 -VisualStudioVersion = 18.0.11109.219 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0131F226-313F-4F7C-9576-7AA726FA9584}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8EBAA9CC-7C39-497D-A925-866E68CFE20A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JobTestDriver", "JobTestDriver\JobTestDriver.csproj", "{B7C455B1-F86A-41CD-91D6-DC041FC83B27}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransactionProcessing.SchedulerService.DataGenerator", "TransactionProcessing.SchedulerService.DataGenerator\TransactionProcessing.SchedulerService.DataGenerator.csproj", "{47C05ABD-A317-48A2-9398-33601407F5E8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransactionDataGenerator", "DataGenerator\TransactionDataGenerator.csproj", "{C980BEBA-3713-0DF7-3DD2-E382DD2A3AB8}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B7C455B1-F86A-41CD-91D6-DC041FC83B27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7C455B1-F86A-41CD-91D6-DC041FC83B27}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B7C455B1-F86A-41CD-91D6-DC041FC83B27}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B7C455B1-F86A-41CD-91D6-DC041FC83B27}.Release|Any CPU.Build.0 = Release|Any CPU - {47C05ABD-A317-48A2-9398-33601407F5E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {47C05ABD-A317-48A2-9398-33601407F5E8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47C05ABD-A317-48A2-9398-33601407F5E8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {47C05ABD-A317-48A2-9398-33601407F5E8}.Release|Any CPU.Build.0 = Release|Any CPU - {C980BEBA-3713-0DF7-3DD2-E382DD2A3AB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C980BEBA-3713-0DF7-3DD2-E382DD2A3AB8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C980BEBA-3713-0DF7-3DD2-E382DD2A3AB8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C980BEBA-3713-0DF7-3DD2-E382DD2A3AB8}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {B7C455B1-F86A-41CD-91D6-DC041FC83B27} = {8EBAA9CC-7C39-497D-A925-866E68CFE20A} - {47C05ABD-A317-48A2-9398-33601407F5E8} = {0131F226-313F-4F7C-9576-7AA726FA9584} - {C980BEBA-3713-0DF7-3DD2-E382DD2A3AB8} = {0131F226-313F-4F7C-9576-7AA726FA9584} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {FCE31FDA-32E8-49AB-8D30-0D36D461CBC1} - EndGlobalSection -EndGlobal diff --git a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI.sln b/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI.sln deleted file mode 100644 index ac4009a..0000000 --- a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30503.244 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransactionProcessor.HealthChecksUI", "TransactionProcessor.HealthChecksUI\TransactionProcessor.HealthChecksUI.csproj", "{48E32489-FA26-40D0-8048-225DE457F85E}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {48E32489-FA26-40D0-8048-225DE457F85E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {48E32489-FA26-40D0-8048-225DE457F85E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {48E32489-FA26-40D0-8048-225DE457F85E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {48E32489-FA26-40D0-8048-225DE457F85E}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {3305EAF9-0814-4939-9767-333CFEC65176} - EndGlobalSection -EndGlobal diff --git a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Program.cs b/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Program.cs deleted file mode 100644 index 59438a0..0000000 --- a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Program.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace TransactionProcessor.HealthChecksUI -{ - using System.IO; - - public static class Program - { - public static void Main(string[] args) - { - Program.CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) - { - //At this stage, we only need our hosting file for ip and ports - FileInfo fi = new FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location); - - IConfigurationRoot config = new ConfigurationBuilder().SetBasePath(fi.Directory.FullName) - .AddJsonFile("hosting.json", optional: true) - .AddJsonFile("hosting.development.json", optional: true) - .AddEnvironmentVariables().Build(); - - IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args); - hostBuilder.UseWindowsService(); - hostBuilder.ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - webBuilder.UseConfiguration(config); - webBuilder.UseKestrel(); - }); - return hostBuilder; - } - } -} diff --git a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Properties/launchSettings.json b/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Properties/launchSettings.json deleted file mode 100644 index b2a0ebd..0000000 --- a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:50716", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "TransactionProcessor.HealthChecksUI": { - "commandName": "Project", - "launchBrowser": true, - "applicationUrl": "http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } - } -} diff --git a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Startup.cs b/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Startup.cs deleted file mode 100644 index d79e0b6..0000000 --- a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/Startup.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace TransactionProcessor.HealthChecksUI -{ - using HealthChecks.UI.Core; - using Microsoft.Extensions.Diagnostics.HealthChecks; - using System.IO; - using System.Net; - using System.Net.Http; - using System.Net.Http.Headers; - using System.Text; - using System.Text.Json; - using System.Text.Json.Serialization; - using System.Threading; - using JsonSerializer = System.Text.Json.JsonSerializer; - - public class Startup - { - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 - public void ConfigureServices(IServiceCollection services){ - services.AddTransient(); - - services.AddHealthChecksUI(settings => - { - settings.UseApiEndpointHttpMessageHandler(ApiEndpointHttpHandler); - settings.UseApiEndpointDelegatingHandler(); - }).AddInMemoryStorage(); - } - - private HttpClientHandler ApiEndpointHttpHandler(IServiceProvider _) - { - return new HttpClientHandler(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseRouting(); - - app.UseEndpoints(endpoints => - { - endpoints.MapHealthChecksUI(); - }); - } - } - - public class CustomHealthReportDelegatingHandler : DelegatingHandler - { - protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - request.Headers.Add("Accept", new[] { "application/json" }); - HttpResponseMessage response = null; - try - { - response = await base.SendAsync(request, cancellationToken); - } - catch(HttpRequestException ex){ - // Just ignore this - JsonSerializerOptions _options = new(JsonSerializerDefaults.Web) - { - Converters = - { - new JsonStringEnumConverter(namingPolicy: null, allowIntegerValues: false) - } - }; - UIHealthReport report = UIHealthReport.CreateFrom(ex); - report.Status = UIHealthStatus.Unhealthy; - String json = JsonSerializer.Serialize(report, _options); - response = new HttpResponseMessage(HttpStatusCode.InternalServerError); - response.Content = new StringContent(json, Encoding.UTF8, "application/json"); - } - return response; - } - } -} diff --git a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI.csproj b/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI.csproj deleted file mode 100644 index 8110112..0000000 --- a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - net10.0 - - - - - - - - - - diff --git a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.Development.json b/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.Development.json deleted file mode 100644 index 8983e0f..0000000 --- a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.Development.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - } -} diff --git a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.json b/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.json deleted file mode 100644 index fb9c4ef..0000000 --- a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "AllowedHosts": "*", - "HealthChecksUI": { - "HealthChecks": [ - { - "Name": "Security Service", - "Uri": "https://192.168.1.163:5001/health" - }, - { - "Name": "Transaction Processor Service", - "Uri": "http://192.168.1.163:5002/health" - }, - { - "Name": "Transaction Processor ACL Service", - "Uri": "http://192.168.1.163:5003/health" - }, - { - "Name": "Estate Management UI", - "Uri": "https://192.168.1.163:5004/health" - }, - { - "Name": "Messaging Service", - "Uri": "http://192.168.1.163:5006/health" - }, - { - "Name": "File Processor Service", - "Uri": "http://192.168.1.163:5009/health" - }, - { - "Name": "Estate Reporting Service", - "Uri": "http://192.168.1.163:5011/health" - } - ], - "EvaluationTimeInSeconds": 300, - "MinimumSecondsBetweenFailureNotifications": 60 - } -} diff --git a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.preproduction.development.json b/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.preproduction.development.json deleted file mode 100644 index 8983e0f..0000000 --- a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.preproduction.development.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - } -} diff --git a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.preproduction.json b/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.preproduction.json deleted file mode 100644 index d2fa5ce..0000000 --- a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.preproduction.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "AllowedHosts": "*", - "HealthChecksUI": { - "HealthChecks": [ - { - "Name": "Security Service", - "Uri": "https://192.168.0.134:5001/healthui" - }, - { - "Name": "Transaction Processor Service", - "Uri": "http://192.168.0.134:5002/healthui" - }, - { - "Name": "Transaction Processor ACL Service", - "Uri": "http://192.168.0.134:5003/healthui" - }, - { - "Name": "Estate Management UI", - "Uri": "https://192.168.0.134:5004/healthui" - }, - { - "Name": "Messaging Service", - "Uri": "http://192.168.0.134:5006/healthui" - }, - { - "Name": "File Processor Service", - "Uri": "http://192.168.0.134:5009/healthui" - } - ], - "EvaluationTimeInSeconds": 300, - "MinimumSecondsBetweenFailureNotifications": 60 - } -} diff --git a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.staging.json b/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.staging.json deleted file mode 100644 index fb9c4ef..0000000 --- a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/appsettings.staging.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "AllowedHosts": "*", - "HealthChecksUI": { - "HealthChecks": [ - { - "Name": "Security Service", - "Uri": "https://192.168.1.163:5001/health" - }, - { - "Name": "Transaction Processor Service", - "Uri": "http://192.168.1.163:5002/health" - }, - { - "Name": "Transaction Processor ACL Service", - "Uri": "http://192.168.1.163:5003/health" - }, - { - "Name": "Estate Management UI", - "Uri": "https://192.168.1.163:5004/health" - }, - { - "Name": "Messaging Service", - "Uri": "http://192.168.1.163:5006/health" - }, - { - "Name": "File Processor Service", - "Uri": "http://192.168.1.163:5009/health" - }, - { - "Name": "Estate Reporting Service", - "Uri": "http://192.168.1.163:5011/health" - } - ], - "EvaluationTimeInSeconds": 300, - "MinimumSecondsBetweenFailureNotifications": 60 - } -} diff --git a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/hosting.json b/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/hosting.json deleted file mode 100644 index 178c3b8..0000000 --- a/TransactionProcessor.HealthChecksUI/TransactionProcessor.HealthChecksUI/hosting.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "urls": "http://*:9500" -} \ No newline at end of file diff --git a/TransactionProcessor.SystemSetupTool/TransactionProcessor.SystemSetupTool.csproj b/TransactionProcessor.SystemSetupTool/TransactionProcessor.SystemSetupTool.csproj index a769358..eed14eb 100644 --- a/TransactionProcessor.SystemSetupTool/TransactionProcessor.SystemSetupTool.csproj +++ b/TransactionProcessor.SystemSetupTool/TransactionProcessor.SystemSetupTool.csproj @@ -21,13 +21,13 @@ - - + + - - - + + + From 81b95666673a0b344186b34b15a1f8d91da711f2 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 31 Aug 2026 16:27:13 +0100 Subject: [PATCH 2/3] :| --- .github/workflows/pullrequest.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 40f6d6d..1ab0be3 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -23,14 +23,12 @@ jobs: - name: Restore Nuget Packages run: | - dotnet restore TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.sln --source ${{ secrets.PUBLICFEEDURL }} --source ${{ secrets.PRIVATEFEED_URL }} dotnet restore TransactionProcessing.MerchantPos/TransactionProcessing.MerchantPos.sln --source ${{ secrets.PUBLICFEEDURL }} --source ${{ secrets.PRIVATEFEED_URL }} dotnet restore TransactionProcessing.MerchantFileProcessor/TransactionProcessing.MerchantFileProcessor.sln --source ${{ secrets.PUBLICFEEDURL }} --source ${{ secrets.PRIVATEFEED_URL }} - name: Build Code run: | - dotnet build TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.sln --configuration Release dotnet build TransactionProcessing.MerchantPos/TransactionProcessing.MerchantPos.sln --configuration Release dotnet build TransactionProcessing.MerchantFileProcessor/TransactionProcessing.MerchantFileProcessor.sln --configuration Release From 91db2f96dafcde6936ed9c16c6ac492ff6da9b5e Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 31 Aug 2026 16:32:11 +0100 Subject: [PATCH 3/3] oops --- .github/workflows/createrelease.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/createrelease.yml b/.github/workflows/createrelease.yml index bc448bc..791cf69 100644 --- a/.github/workflows/createrelease.yml +++ b/.github/workflows/createrelease.yml @@ -26,7 +26,6 @@ jobs: - name: Restore Nuget Packages run: | - dotnet restore TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.sln --source ${{ secrets.PUBLICFEEDURL }} --source ${{ secrets.PRIVATEFEED_URL }} dotnet restore TransactionProcessing.MerchantPos/TransactionProcessing.MerchantPos.sln --source ${{ secrets.PUBLICFEEDURL }} --source ${{ secrets.PRIVATEFEED_URL }} dotnet restore TransactionProcessing.MerchantFileProcessor/TransactionProcessing.MerchantFileProcessor.sln --source ${{ secrets.PUBLICFEEDURL }} --source ${{ secrets.PRIVATEFEED_URL }}