diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploads/GenerateFileUploadsBootstrapper.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploads/GenerateFileUploadsBootstrapper.cs index 5eabbc8..2b73b06 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploads/GenerateFileUploadsBootstrapper.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploads/GenerateFileUploadsBootstrapper.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Quartz; using SecurityService.Client; + using TransactionProcessor.Client; /// /// @@ -22,6 +23,7 @@ public override void ConfigureServiceAdditional(IJobExecutionContext jobExecutio { this.Services.AddSingleton(); this.Services.AddSingleton(); + this.Services.AddSingleton(); this.Services.AddSingleton>(container => serviceName => { return jobExecutionContext.MergedJobDataMap.GetString(serviceName); }); } diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploads/GenerateFileUploadsJob.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploads/GenerateFileUploadsJob.cs index 420cc87..d5ede4d 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploads/GenerateFileUploadsJob.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploads/GenerateFileUploadsJob.cs @@ -8,6 +8,7 @@ using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; + using DataGeneration; using EstateManagement.Client; using EstateManagement.DataTransferObjects.Requests; using EstateManagement.DataTransferObjects.Responses; @@ -15,6 +16,7 @@ using Quartz.Impl; using SecurityService.Client; using SecurityService.DataTransferObjects.Responses; + using TransactionProcessor.Client; /// /// @@ -24,27 +26,17 @@ public class GenerateFileUploadsJob : IJob { #region Fields - - /// - /// The base address function - /// + private Func baseAddressFunc; - - /// - /// The bootstrapper - /// + private readonly IBootstrapper Bootstrapper; - - /// - /// The estate client - /// + private IEstateClient EstateClient; - - /// - /// The security service client - /// + private ISecurityServiceClient SecurityServiceClient; + private ITransactionProcessorClient TransactionProcessorClient; + #endregion #region Constructors @@ -61,309 +53,48 @@ public GenerateFileUploadsJob(Func bootstrapperResolver) #endregion #region Methods - - /// - /// Called by the when a - /// fires that is associated with the . - /// - /// The execution context. - /// - /// The implementation may wish to set a result object on the - /// JobExecutionContext before this method exits. The result itself - /// is meaningless to Quartz, but may be informative to - /// s or - /// s that are watching the job's - /// execution. - /// public async Task Execute(IJobExecutionContext context) { this.Bootstrapper.ConfigureServices(context); - + String clientId = context.MergedJobDataMap.GetString("ClientId"); + String clientSecret = context.MergedJobDataMap.GetString("ClientSecret"); Guid estateId = context.MergedJobDataMap.GetGuidValueFromString("EstateId"); Guid merchantId = context.MergedJobDataMap.GetGuidValueFromString("MerchantId"); - String contractsToSkip = context.MergedJobDataMap.GetString("contractsToSkip"); - + this.SecurityServiceClient = this.Bootstrapper.GetService(); this.EstateClient = this.Bootstrapper.GetService(); + this.TransactionProcessorClient = this.Bootstrapper.GetService(); this.baseAddressFunc = this.Bootstrapper.GetService>(); - - await this.GenerateFileUploads(estateId, merchantId,contractsToSkip, context.CancellationToken); - } - - /// - /// Generates the file uploads. - /// - /// The estate identifier. - /// The merchant identifier. - /// The cancellation token. - private async Task GenerateFileUploads(Guid estateId, - Guid merchantId, - String contractsToSkip, - CancellationToken cancellationToken) - { + + ITransactionDataGenerator g = new TransactionDataGenerator(this.SecurityServiceClient, + this.EstateClient, + this.TransactionProcessorClient, + this.baseAddressFunc("FileProcessorApi"), + this.baseAddressFunc("TestHostApi"), + clientId, + clientSecret, + RunningMode.Live); + String accessToken = await this.GetToken(clientId, + clientSecret, + context.CancellationToken); + + MerchantResponse merchant = await this.EstateClient.GetMerchant(accessToken, estateId, merchantId, context.CancellationToken); + + List contracts = await this.EstateClient.GetMerchantContracts(accessToken, merchant.EstateId, merchant.MerchantId, context.CancellationToken); DateTime fileDate = DateTime.Now; - - // get a token - String accessToken = await this.GetToken(cancellationToken); - - MerchantResponse merchant = await this.EstateClient.GetMerchant(accessToken, estateId, merchantId, cancellationToken); - - Random r = new Random(); - - // get a number of transactions to generate - Int32 numberOfSales = r.Next(5, 15); - - List contracts = await this.EstateClient.GetMerchantContracts(accessToken, merchant.EstateId, merchant.MerchantId, cancellationToken); - - if (String.IsNullOrEmpty(contractsToSkip) == false) - { - String[] skipContracts = contractsToSkip.Split('|'); - contracts = contracts.Where(c => skipContracts.Contains(c.Description) == false).ToList(); - } - - EstateResponse estate = await this.EstateClient.GetEstate(accessToken, merchant.EstateId, cancellationToken); - - SecurityUserResponse estateUser = estate.SecurityUsers.FirstOrDefault(); - - foreach (MerchantOperatorResponse merchantOperator in merchant.Operators) - { - List fileData = null; - // get the contract - var contract = contracts.SingleOrDefault(c => c.OperatorId == merchantOperator.OperatorId); - - // Only process if we find the contract - if (contract != null) { - - if (merchantOperator.Name == "Voucher") { - // Generate a voucher file - var voucherFile = this.GenerateVoucherFile(fileDate, contract.Description.Replace("Contract", ""), numberOfSales); - fileData = voucherFile.fileLines; - // Need to make a deposit for this amount - last sale - Decimal depositAmount = voucherFile.totalValue - voucherFile.lastSale; - await this.MakeMerchantDeposit(accessToken, merchant, depositAmount, fileDate.AddSeconds(1), cancellationToken); - } - else { - // generate a topup file - var topupFile = this.GenerateTopupFile(fileDate, numberOfSales); - fileData = topupFile.fileLines; - // Need to make a deposit for this amount - last sale - Decimal depositAmount = topupFile.totalValue - topupFile.lastSale; - await this.MakeMerchantDeposit(accessToken, merchant, depositAmount, fileDate.AddSeconds(2), cancellationToken); - } - - // Write this file to disk - Directory.CreateDirectory($"/home/txnproc/txngenerator/{merchantOperator.Name}"); - using(StreamWriter sw = - new - StreamWriter($"/home/txnproc/txngenerator/{merchantOperator.Name}/{contract.Description.Replace("Contract", "")}-{fileDate:yyyy-MM-dd-HH-mm-ss}")) { - foreach (String fileLine in fileData) { - sw.WriteLine(fileLine); - } - } - - // Upload the generated files for this merchant/operator - // Get the files - var files = Directory.GetFiles($"/home/txnproc/txngenerator/{merchantOperator.Name}"); - - var fileDateTime = fileDate.AddHours(DateTime.Now.Hour).AddMinutes(DateTime.Now.Minute).AddSeconds(DateTime.Now.Second); - - foreach (String file in files) { - var fileProfileId = this.GetFileProfileIdFromOperator(merchantOperator.Name, cancellationToken); - - await this.UploadFile(accessToken, - file, - merchant.EstateId, - merchant.MerchantId, - fileProfileId, - estateUser.SecurityUserId, - fileDateTime, - cancellationToken); - - // Remove file once uploaded - File.Delete(file); - } - } + foreach (ContractResponse contract in contracts){ + // Generate a file and upload + await g.SendUploadFile(fileDate, contract, merchant, context.CancellationToken); } } - /// - /// Generates the topup file. - /// - /// The date time. - /// The number of lines. - /// - private (List fileLines, Decimal totalValue, Decimal lastSale) GenerateTopupFile(DateTime dateTime, - Int32 numberOfLines) - { - List fileLines = new List(); - Decimal totalValue = 0; - Decimal lastSale = 0; - String mobileNumber = "07777777305"; - Random r = new Random(); - - fileLines.Add($"H,{dateTime:yyyy-MM-dd-HH-mm-ss}"); - - for (Int32 i = 0; i < numberOfLines; i++) - { - Int32 amount = r.Next(75, 250); - totalValue += amount; - lastSale = amount; - fileLines.Add($"D,{mobileNumber},{amount}"); - } - - fileLines.Add($"T,{numberOfLines}"); - - return (fileLines, totalValue, lastSale); - } - - /// - /// Generates the voucher file. - /// - /// The date time. - /// Name of the issuer. - /// The number of lines. - /// - private (List fileLines, Decimal totalValue, Decimal lastSale) GenerateVoucherFile(DateTime dateTime, - String issuerName, - Int32 numberOfLines) - { - // Build the header - List fileLines = new List(); - fileLines.Add($"H,{dateTime:yyyy-MM-dd-HH-mm-ss}"); - String emailAddress = "testrecipient@email.com"; - String mobileNumber = "07777777305"; - Random r = new Random(); - Decimal totalValue = 0; - Decimal lastSale = 0; - - for (Int32 i = 0; i < numberOfLines; i++) - { - Int32 amount = r.Next(75, 250); - totalValue += amount; - lastSale = amount; - if (i % 2 == 0) - { - fileLines.Add($"D,{issuerName},{emailAddress},{amount}"); - } - else - { - fileLines.Add($"D,{issuerName},{mobileNumber},{amount}"); - } - } - - fileLines.Add($"T,{numberOfLines}"); - - return (fileLines, totalValue, lastSale); - } - - /// - /// Gets the file profile identifier from operator. - /// - /// Name of the operator. - /// The cancellation token. - /// - private Guid GetFileProfileIdFromOperator(String operatorName, - CancellationToken cancellationToken) + private async Task GetToken(String clientId, String clientSecret, 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; - } - } - - /// - /// Gets the token. - /// - /// The cancellation token. - /// - private async Task GetToken(CancellationToken cancellationToken) - { - // Get a token to talk to the estate service - String clientId = "serviceClient"; - String clientSecret = "d192cbc46d834d0da90e8a9d50ded543"; - TokenResponse token = await this.SecurityServiceClient.GetToken(clientId, clientSecret, cancellationToken); return token.AccessToken; } - /// - /// Makes the merchant deposit. - /// - /// The access token. - /// The merchant. - /// The deposit amount. - /// The date time. - /// The cancellation token. - private async Task MakeMerchantDeposit(String accessToken, - MerchantResponse merchant, - Decimal depositAmount, - DateTime dateTime, - CancellationToken cancellationToken) - { - await this.EstateClient.MakeMerchantDeposit(accessToken, - merchant.EstateId, - merchant.MerchantId, - new MakeMerchantDepositRequest - { - Amount = depositAmount, - DepositDateTime = dateTime.AddSeconds(55), - Reference = "Test Data Gen Deposit" - }, - cancellationToken); - Console.WriteLine($"Deposit made for Merchant [{merchant.MerchantName}]"); - } - - /// - /// Uploads the file. - /// - /// The access token. - /// The file path. - /// The estate identifier. - /// The merchant identifier. - /// The file profile identifier. - /// The user identifier. - /// The file date time. - /// The cancellation token. - /// - private async Task UploadFile(String accessToken, - String filePath, - Guid estateId, - Guid merchantId, - Guid fileProfileId, - Guid userId, - DateTime fileDateTime, - CancellationToken cancellationToken) - { - var client = new HttpClient(); - var formData = new MultipartFormDataContent(); - - var fileContent = new ByteArrayContent(await File.ReadAllBytesAsync(filePath)); - fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data"); - formData.Add(fileContent, "file", Path.GetFileName(filePath)); - formData.Add(new StringContent(estateId.ToString()), "request.EstateId"); - formData.Add(new StringContent(merchantId.ToString()), "request.MerchantId"); - formData.Add(new StringContent(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"); - - var request = new HttpRequestMessage(HttpMethod.Post, $"{this.baseAddressFunc("FileProcessorApi")}/api/files") - { - Content = formData, - }; - request.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken); - var response = await client.SendAsync(request, cancellationToken); - - return response; - } - #endregion } } \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateTransactions/GenerateTransactionsJob.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateTransactions/GenerateTransactionsJob.cs index a704338..85564b1 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateTransactions/GenerateTransactionsJob.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateTransactions/GenerateTransactionsJob.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; + using DataGeneration; using EstateManagement.Client; using EstateManagement.DataTransferObjects.Requests; using EstateManagement.DataTransferObjects.Responses; @@ -24,32 +25,15 @@ public class GenerateTransactionsJob : IJob { #region Fields + + private Func baseAddressFunc; - /// - /// The base address function - /// - private static Func baseAddressFunc; - - /// - /// The bootstrapper - /// private readonly IBootstrapper Bootstrapper; - /// - /// The estate client - /// private IEstateClient EstateClient; - private String TestHostApi; - - /// - /// The security service client - /// private ISecurityServiceClient SecurityServiceClient; - /// - /// The transaction processor client - /// private ITransactionProcessorClient TransactionProcessorClient; #endregion @@ -68,435 +52,76 @@ public GenerateTransactionsJob(Func bootstrapperResolver) #endregion #region Methods - - /// - /// Called by the when a - /// fires that is associated with the . - /// - /// The execution context. - /// - /// The implementation may wish to set a result object on the - /// JobExecutionContext before this method exits. The result itself - /// is meaningless to Quartz, but may be informative to - /// s or - /// s that are watching the job's - /// execution. - /// + public async Task Execute(IJobExecutionContext context) { try { this.Bootstrapper.ConfigureServices(context); + String clientId = context.MergedJobDataMap.GetString("ClientId"); + String clientSecret = context.MergedJobDataMap.GetString("ClientSecret"); Guid estateId = context.MergedJobDataMap.GetGuidValueFromString("EstateId"); Guid merchantId = context.MergedJobDataMap.GetGuidValueFromString("MerchantId"); Boolean requireLogon = context.MergedJobDataMap.GetBooleanValueFromString("requireLogon"); - String contractsToSkip = context.MergedJobDataMap.GetString("contractsToSkip"); - this.TestHostApi = context.MergedJobDataMap.GetString("TestHostApi"); - + this.SecurityServiceClient = this.Bootstrapper.GetService(); this.TransactionProcessorClient = this.Bootstrapper.GetService(); this.EstateClient = this.Bootstrapper.GetService(); + this.baseAddressFunc = this.Bootstrapper.GetService>(); - await this.GenerateTransactions(estateId, merchantId, requireLogon, contractsToSkip, context.CancellationToken); - } - catch(Exception e) - { - // TODO: Log the error - } - } + ITransactionDataGenerator g = new TransactionDataGenerator(this.SecurityServiceClient, + this.EstateClient, + this.TransactionProcessorClient, + this.baseAddressFunc("FileProcessorApi"), + this.baseAddressFunc("TestHostApi"), + clientId, + clientSecret, + RunningMode.Live); - /// - /// Creates the sale requests. - /// - /// The access token. - /// The merchant. - /// The date time. - /// The cancellation token. - /// - private async Task> CreateSaleRequests(String accessToken, - MerchantResponse merchant, - DateTime dateTime, - String contractsToSkip, - CancellationToken cancellationToken) - { - List contracts = await this.EstateClient.GetMerchantContracts(accessToken, merchant.EstateId, merchant.MerchantId, cancellationToken); - - if (String.IsNullOrEmpty(contractsToSkip) == false) { - String[] skipContracts = contractsToSkip.Split('|'); - contracts = contracts.Where(c => skipContracts.Contains(c.Description) == true).ToList(); - } + // get a token + String accessToken = await this.GetToken(clientId, + clientSecret, context.CancellationToken); - List<(SaleTransactionRequest request, Decimal amount)> saleRequests = new List<(SaleTransactionRequest request, Decimal amount)>(); + // get the merchant + MerchantResponse merchant = await this.EstateClient.GetMerchant(accessToken, estateId, merchantId, context.CancellationToken); - Random r = new Random(); - Int32 transactionNumber = 1; - // get a number of transactions to generate - Int32 numberOfSales = r.Next(2, 4); + Int32 transactionCount = 0; + DateTime transactionDate = DateTime.Now; - for (Int32 i = 0; i < numberOfSales; i++) - { - var requests = await this.CreateSaleTransactionRequest(merchant, dateTime, contracts, r, transactionNumber); + if (requireLogon) + { + // Do a logon transaction for the merchant + await g.PerformMerchantLogon(transactionDate, merchant, context.CancellationToken); - saleRequests.AddRange(requests); - transactionNumber++; - } - - return saleRequests; - } + // Get the merchants contracts + List contracts = await g.GetMerchantContracts(merchant, context.CancellationToken); - private async Task> CreateSaleTransactionRequest(MerchantResponse merchant, DateTime dateTime, List contracts, Random r, Int32 transactionNumber){ - // Pick a contract - ContractResponse contract = contracts[r.Next(0, contracts.Count)]; + foreach (ContractResponse contract in contracts) + { + // Generate and send some sales + await g.SendSales(transactionDate, merchant, contract, context.CancellationToken); - // Pick a product - ContractProduct product = contract.Products[r.Next(0, contract.Products.Count)]; + // Generate a file and upload + await g.SendUploadFile(transactionDate, contract, merchant, context.CancellationToken); + } - Decimal amount = 0; - if (product.Value.HasValue){ - amount = product.Value.Value; - } - else{ - // generate an amount - amount = r.Next(9, 250); - } - - // Generate the time - DateTime transactionDateTime = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, 0); - - // Build the metadata - Dictionary requestMetaData = new Dictionary(); - requestMetaData.Add("Amount", amount.ToString()); - - List<(SaleTransactionRequest request, Decimal amount)> requests = new List<(SaleTransactionRequest request, Decimal amount)>(); - - ProductType productType = GenerateTransactionsJob.GetProductType(contract.OperatorName); - if (productType != ProductType.BillPayment){ - String operatorName = GenerateTransactionsJob.GetOperatorName(contract); - if (productType == ProductType.MobileTopup){ - requestMetaData.Add("CustomerAccountNumber", "1234567890"); - } - else if (productType == ProductType.Voucher){ - requestMetaData.Add("RecipientMobile", "1234567890"); - } - - 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 = transactionDateTime.AddSeconds(r.Next(0, 59)), - TransactionNumber = transactionNumber.ToString(), - OperatorIdentifier = contract.OperatorName, - ProductId = product.ProductId - }; - requests.Add((request, amount)); - } - else{ - (Int32 accountNumber, String accountName, Decimal balance) billDetails = await CreateBill(contract, amount, r); - - if (billDetails == default) - return 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" } - }; - - SaleTransactionRequest getAccountRequest = new SaleTransactionRequest - { - AdditionalTransactionMetadata = getAccountRequestMetaData, - ContractId = contract.ContractId, - CustomerEmailAddress = string.Empty, - DeviceIdentifier = deviceIdentifier, - MerchantId = merchant.MerchantId, - EstateId = merchant.EstateId, - TransactionType = "Sale", - TransactionDateTime = transactionDateTime.AddSeconds(r.Next(0, 59)), - TransactionNumber = transactionNumber.ToString(), - OperatorIdentifier = contract.OperatorName, - ProductId = product.ProductId - }; - - requests.Add((getAccountRequest,0)); - - // Second request is Make Payment - var makePaymentRequestMetaData = new Dictionary{ - { "CustomerAccountNumber", billDetails.accountNumber.ToString() }, - { "CustomerName", billDetails.accountName}, - { "MobileNumber", "1234567890"}, - { "Amount", amount.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(r.Next(0, 59)), - TransactionNumber = transactionNumber.ToString(), - OperatorIdentifier = contract.OperatorName, - ProductId = product.ProductId - }; - - requests.Add((makePaymentRequest, amount)); - - } - - return requests; - } - - private async Task<(Int32 accountNumber, String accountName, Decimal balance)> CreateBill(ContractResponse contract, Decimal amount, Random r) - { - if (contract.OperatorName == "PataPawa PostPay"){ - - Int32 accountNumber = r.Next(1, 100000); - - HttpClient httpClient = new HttpClient(); - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"{this.TestHostApi}/api/developer/patapawapostpay/createbill"); - var body = new{ - due_date = DateTime.Now.AddDays(1), - amount = amount * 100, - account_number = accountNumber, - account_name = "Test Account 1" - }; - request.Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); - HttpResponseMessage response = await httpClient.SendAsync(request); - - if (response.IsSuccessStatusCode){ - return (body.account_number, body.account_name, body.amount); + Console.WriteLine($"Logon sent for Merchant [{merchant.MerchantName}]"); } } - - return default; - } - - /// - /// Does the logon transaction. - /// - /// The access token. - /// The merchant. - /// The date. - /// The cancellation token. - private async Task DoLogonTransaction(String accessToken, - MerchantResponse merchant, - DateTime date, - CancellationToken cancellationToken) - { - String deviceIdentifier = merchant.Devices.Single().Value; - LogonTransactionRequest logonTransactionRequest = new LogonTransactionRequest - { - DeviceIdentifier = deviceIdentifier, - EstateId = merchant.EstateId, - MerchantId = merchant.MerchantId, - TransactionDateTime = date.AddMinutes(1), - TransactionNumber = "1", - TransactionType = "Logon" - }; - - SerialisedMessage requestSerialisedMessage = new SerialisedMessage(); - requestSerialisedMessage.Metadata.Add("estate_id", merchant.EstateId.ToString()); - requestSerialisedMessage.Metadata.Add("merchant_id", merchant.MerchantId.ToString()); - requestSerialisedMessage.SerialisedData = JsonConvert.SerializeObject(logonTransactionRequest, - new JsonSerializerSettings - { - TypeNameHandling = TypeNameHandling.All - }); - - SerialisedMessage responseSerialisedMessage = - await this.TransactionProcessorClient.PerformTransaction(accessToken, requestSerialisedMessage, cancellationToken); - - LogonTransactionResponse logonTransactionResponse = JsonConvert.DeserializeObject(responseSerialisedMessage.SerialisedData); - } - - /// - /// Does the sale transaction. - /// - /// The access token. - /// The sale transaction request. - /// The cancellation token. - private async Task DoSaleTransaction(String accessToken, - SaleTransactionRequest saleTransactionRequest, - CancellationToken cancellationToken) - { - try - { - SerialisedMessage requestSerialisedMessage = new SerialisedMessage(); - requestSerialisedMessage.Metadata.Add("estate_id", saleTransactionRequest.EstateId.ToString()); - requestSerialisedMessage.Metadata.Add("merchant_id", saleTransactionRequest.MerchantId.ToString()); - requestSerialisedMessage.SerialisedData = JsonConvert.SerializeObject(saleTransactionRequest, - new JsonSerializerSettings - { - TypeNameHandling = TypeNameHandling.All - }); - - SerialisedMessage responseSerialisedMessage = - await this.TransactionProcessorClient.PerformTransaction(accessToken, requestSerialisedMessage, cancellationToken); - - SaleTransactionResponse saleTransactionResponse = JsonConvert.DeserializeObject(responseSerialisedMessage.SerialisedData); - } catch(Exception e) { - Console.WriteLine(e); - } - } - - /// - /// Generates the transactions. - /// - /// The estate identifier. - /// The merchant identifier. - /// if set to true [requires logon]. - /// The cancellation token. - /// - private async Task GenerateTransactions(Guid estateId, - Guid merchantId, - Boolean requiresLogon, - String contractsToSkip, - CancellationToken cancellationToken){ - DateTime transactionDate = DateTime.Now; - - // get a token - String accessToken = await this.GetToken(cancellationToken); - - // get the merchant - MerchantResponse merchant = await this.EstateClient.GetMerchant(accessToken, estateId, merchantId, cancellationToken); - - Int32 transactionCount = 0; - - if (requiresLogon){ - // Do a logon transaction for the merchant - await this.DoLogonTransaction(accessToken, merchant, transactionDate, cancellationToken); - - Console.WriteLine($"Logon sent for Merchant [{merchant.MerchantName}]"); - } - - // Now generate some sales - List<(SaleTransactionRequest request, Decimal amount)> saleRequests = await this.CreateSaleRequests(accessToken, merchant, transactionDate, contractsToSkip, cancellationToken); - - // Work out how much of a deposit the merchant needs (minus 1 sale) - IEnumerable amountList = saleRequests.Select(s => s.amount).ToList(); - - Decimal depositAmount = amountList.TakeLast(amountList.Count() - 1).Sum(a => a); - - await this.MakeMerchantDeposit(accessToken, merchant, depositAmount, transactionDate, cancellationToken); - - // Now send the sales - saleRequests = saleRequests.OrderBy(s => s.request.TransactionDateTime).ToList(); - foreach ((SaleTransactionRequest request, Decimal amount) saleTransactionRequest in saleRequests){ - await this.DoSaleTransaction(accessToken, saleTransactionRequest.request, cancellationToken); - Console.WriteLine($"Sale sent for Merchant [{merchant.MerchantName}]"); - transactionCount++; - } - } - - /// - /// Gets the name of the operator. - /// - /// The contract response. - /// - private static String GetOperatorName(ContractResponse contractResponse) - { - String operatorName = null; - ProductType productType = GenerateTransactionsJob.GetProductType(contractResponse.OperatorName); - switch(productType) - { - case ProductType.Voucher: - operatorName = contractResponse.Description; - break; - default: - operatorName = contractResponse.OperatorName; - break; - } - - return operatorName; - } - - /// - /// Gets the type of the product. - /// - /// Name of the operator. - /// - private static 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": - productType = ProductType.BillPayment; - break; + // TODO: Log the error } - - return productType; } - /// - /// Gets the token. - /// - /// The cancellation token. - /// - private async Task GetToken(CancellationToken cancellationToken) + private async Task GetToken(String clientId, String clientSecret, CancellationToken cancellationToken) { - // Get a token to talk to the estate service - String clientId = "serviceClient"; - String clientSecret = "d192cbc46d834d0da90e8a9d50ded543"; - TokenResponse token = await this.SecurityServiceClient.GetToken(clientId, clientSecret, cancellationToken); return token.AccessToken; } - /// - /// Makes the merchant deposit. - /// - /// The access token. - /// The merchant. - /// The deposit amount. - /// The date time. - /// The cancellation token. - private async Task MakeMerchantDeposit(String accessToken, - MerchantResponse merchant, - Decimal depositAmount, - DateTime dateTime, - CancellationToken cancellationToken) - { - if (depositAmount == 0) - return; - - await this.EstateClient.MakeMerchantDeposit(accessToken, - merchant.EstateId, - merchant.MerchantId, - new MakeMerchantDepositRequest - { - Amount = depositAmount, - DepositDateTime = dateTime.AddSeconds(55), - Reference = "Test Data Gen Deposit" - }, - cancellationToken); - Console.WriteLine($"Deposit made for Merchant [{merchant.MerchantName}]"); - } - - #endregion + #endregion } } \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlement/ProcessSettlementJob.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlement/ProcessSettlementJob.cs index 68e64c8..6048bb4 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlement/ProcessSettlementJob.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlement/ProcessSettlementJob.cs @@ -7,37 +7,35 @@ namespace TransactionProcessing.SchedulerService.Jobs { using System.Threading; + using EstateManagement.Client; using Quartz; using SecurityService.Client; using SecurityService.DataTransferObjects.Responses; + using TransactionProcessing.DataGeneration; using TransactionProcessor.Client; public class ProcessSettlementJob : IJob { + private Func baseAddressFunc; + private readonly IBootstrapper Bootstrapper; - public ProcessSettlementJob(Func bootstrapperResolver) - { - this.Bootstrapper = bootstrapperResolver(nameof(ProcessSettlementJob)); - } + private IEstateClient EstateClient; - /// - /// The security service client - /// private ISecurityServiceClient SecurityServiceClient; private ITransactionProcessorClient TransactionProcessorClient; - /// - /// Gets the token. - /// - /// The cancellation token. - /// - private async Task GetToken(CancellationToken cancellationToken) + public ProcessSettlementJob(Func bootstrapperResolver) + { + this.Bootstrapper = bootstrapperResolver(nameof(ProcessSettlementJob)); + } + + private async Task GetToken(String clientId, + String clientSecret, + CancellationToken cancellationToken) { - // Get a token to talk to the estate service - String clientId = "serviceClient"; - String clientSecret = "d192cbc46d834d0da90e8a9d50ded543"; + TokenResponse token = await this.SecurityServiceClient.GetToken(clientId, clientSecret, cancellationToken); @@ -46,24 +44,26 @@ private async Task GetToken(CancellationToken cancellationToken) public async Task Execute(IJobExecutionContext context) { - try - { - this.Bootstrapper.ConfigureServices(context); + this.Bootstrapper.ConfigureServices(context); + String clientId = context.MergedJobDataMap.GetString("ClientId"); + String clientSecret = context.MergedJobDataMap.GetString("ClientSecret"); + Guid estateId = context.MergedJobDataMap.GetGuidValueFromString("EstateId"); - Guid estateId = context.MergedJobDataMap.GetGuidValueFromString("EstateId"); + this.SecurityServiceClient = this.Bootstrapper.GetService(); + this.TransactionProcessorClient = this.Bootstrapper.GetService(); + this.EstateClient = this.Bootstrapper.GetService(); + this.baseAddressFunc = this.Bootstrapper.GetService>(); + + ITransactionDataGenerator g = new TransactionDataGenerator(this.SecurityServiceClient, + this.EstateClient, + this.TransactionProcessorClient, + this.baseAddressFunc("FileProcessorApi"), + this.baseAddressFunc("TestHostApi"), + clientId, + clientSecret, + RunningMode.Live); - this.SecurityServiceClient = this.Bootstrapper.GetService(); - this.TransactionProcessorClient = this.Bootstrapper.GetService(); - String token = await this.GetToken(context.CancellationToken); - await this.TransactionProcessorClient.ProcessSettlement(token, DateTime.Now.Date, estateId, context.CancellationToken); - } - catch (Exception e) - { - context.Result = new - { - ErrorMessage = e.Message - }; - } + await g.PerformSettlement(DateTime.Now.Date, estateId, context.CancellationToken); } } } diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlement/ProcessSettlementJobBootstrapper.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlement/ProcessSettlementJobBootstrapper.cs index 5e21547..ebef493 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlement/ProcessSettlementJobBootstrapper.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlement/ProcessSettlementJobBootstrapper.cs @@ -1,6 +1,7 @@ namespace TransactionProcessing.SchedulerService.Jobs { using System; + using EstateManagement.Client; using Microsoft.Extensions.DependencyInjection; using Quartz; using SecurityService.Client; @@ -17,6 +18,7 @@ public class ProcessSettlementJobBootstrapper : BaseBoostrapper public override void ConfigureServiceAdditional(IJobExecutionContext jobExecutionContext) { this.Services.AddSingleton(); + this.Services.AddSingleton(); this.Services.AddSingleton(); this.Services.AddSingleton>(container => serviceName => { return jobExecutionContext.MergedJobDataMap.GetString(serviceName); }); diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj index df828f8..0303e1a 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj @@ -5,11 +5,11 @@ - + - + - - + +