Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,8 @@ await g.MakeFloatDeposit(dateTime, estateId, contractResponse.ContractId,
foreach (ContractResponse contract in getMerchantContractsResult.Data) {
// Generate and send some sales

await g.SendSales(dateTime, merchant, contract, 0, cancellationToken);
await g.SendSales(dateTime, merchant, contract, 0,0, cancellationToken);
}

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Task<Result> PerformMerchantSettlement(DateTime dateTime,
Guid estateId,
Guid merchantId,
CancellationToken cancellationToken);
Task<Result> SendSales(DateTime dateTime, MerchantResponse merchant, ContractResponse contract, Int32 numberOfSales, CancellationToken cancellationToken);
Task<Result> SendSales(DateTime dateTime, MerchantResponse merchant, ContractResponse contract, Int32 numberOfSales, Int32 timeDelay, CancellationToken cancellationToken);
Task<Result> SendUploadFile(DateTime dateTime, ContractResponse contract, MerchantResponse merchant, Guid userId, CancellationToken cancellationToken);
Task<Result<MerchantResponse>> GetMerchant(Guid estateId, Guid merchantId, CancellationToken cancellationToken);
Task<Result> GenerateMerchantStatement(Guid estateId, Guid merchantId, DateTime statementDateTime, CancellationToken cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;
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.Text;
using TransactionProcessor.Client;
using TransactionProcessor.DataTransferObjects;
using TransactionProcessor.DataTransferObjects.Requests.Merchant;
Expand All @@ -21,7 +22,7 @@
private readonly String TransactionProcessorApi;
private readonly String FileProcessorApi;

public TransactionDataGeneratorService(ISecurityServiceClient securityServiceClient,

Check warning on line 25 in TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

Non-nullable field 'ClientToken' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 25 in TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

Non-nullable field 'TokenResponse' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.
ITransactionProcessorClient transactionProcessorClient,
String transactionProcessorApi,
String fileProcessorApi,
Expand Down Expand Up @@ -201,62 +202,55 @@
MerchantResponse merchant,
ContractResponse contract,
Int32 numberOfSales,
Int32 timeDelay,
CancellationToken cancellationToken) {
List<SaleTransactionRequest> salesToSend = new List<SaleTransactionRequest>();
Decimal depositAmount = 0;
(Int32 accountNumber, String accountName, Decimal balance) billDetails = default;
(Int32 meterNumber, String customerName, Decimal amount) meterDetails = default;

foreach (ContractProduct contractProduct in contract.Products)
{
this.WriteTrace($"product [{contractProduct.DisplayText}]");

List<(SaleTransactionRequest request, Decimal amount)> saleRequests = null;
// Get a number of sales to be sent
if (numberOfSales == 0)
{
numberOfSales = this.r.Next(2, 10);
}
// Step 2: Decide how many total transactions to generate in this run
numberOfSales = this.r.Next(1, 6); // e.g. 1–5 transactions per run
List<(SaleTransactionRequest request, Decimal amount)> saleRequests = null;

Check warning on line 214 in TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

Converting null literal or possible null value to non-nullable type.
for (int i = 0; i < numberOfSales; i++) {
ContractProduct? contractProduct = contract.Products[this.r.Next(contract.Products.Count)];

for (Int32 i = 1; i <= numberOfSales; i++)
{
ProductSubType productSubType = this.GetProductSubType(contract.OperatorName);
// Spread transactions randomly across 5 minutes
int delayMs = this.r.Next(0, timeDelay * 60 * 1000);

if (productSubType == ProductSubType.BillPaymentPostPay)
{
// Create a bill for this sale
billDetails = await this.CreateBillPaymentBill(contract.OperatorName, contractProduct, cancellationToken);
}
await Task.Delay(delayMs);
ProductSubType productSubType = this.GetProductSubType(contract.OperatorName);

if (productSubType == ProductSubType.BillPaymentPrePay)
{
// Create a meter
meterDetails = await this.CreateBillPaymentMeter(contract.OperatorName, contractProduct, cancellationToken);
}
if (productSubType == ProductSubType.BillPaymentPostPay) {
// Create a bill for this sale
billDetails = await this.CreateBillPaymentBill(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 Exception($"Product Sub Type [{productSubType}] not yet supported")
};
if (productSubType == ProductSubType.BillPaymentPrePay) {
// Create a meter
meterDetails = await this.CreateBillPaymentMeter(contract.OperatorName, contractProduct, cancellationToken);
}

// Add the value of the sale to the deposit amount
Boolean addToDeposit = i switch
{
_ when i == numberOfSales => false,
_ => true
};
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 Exception($"Product Sub Type [{productSubType}] not yet supported")
};

if (addToDeposit)
{
depositAmount += saleRequests.Sum(sr => sr.amount);
}
// Add the value of the sale to the deposit amount
Boolean addToDeposit = i switch {
_ when i == numberOfSales => false,
_ => true
};

salesToSend.AddRange(saleRequests.Select(s => s.request));
if (addToDeposit) {
depositAmount += saleRequests.Sum(sr => sr.amount);
}

salesToSend.AddRange(saleRequests.Select(s => s.request));

}

// Build up a deposit (minus the last sale amount)
Expand All @@ -274,24 +268,19 @@
Int32 salesSent = 0;
IOrderedEnumerable<SaleTransactionRequest> orderedSales = salesToSend.OrderBy(s => s.TransactionDateTime);
// Send the sales to the host
foreach (SaleTransactionRequest sale in orderedSales)
{
foreach (SaleTransactionRequest sale in orderedSales) {
sale.TransactionNumber = this.GetTransactionNumber().ToString();
Result<SerialisedMessage> saleResult = await this.SendSaleTransaction(merchant, sale, cancellationToken);
if (saleResult.IsSuccess)
{
if (saleResult.IsSuccess) {
salesSent++;
}
//var random = new Random();
//int delaySeconds = random.Next(5, 10); // 30–60 inclusive
//await Task.Delay(TimeSpan.FromSeconds(delaySeconds), cancellationToken);
}

if (salesSent == 0)
{
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();
}
Expand Down Expand Up @@ -359,7 +348,7 @@
};

request.Headers.Authorization = new AuthenticationHeaderValue("bearer", tokenResult.Data);
HttpResponseMessage response = null;

Check warning on line 351 in TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

Converting null literal or possible null value to non-nullable type.

try
{
Expand All @@ -380,7 +369,7 @@
}
}

private static async Task<Guid> GetFileProfileIdFromOperator(String operatorName, CancellationToken cancellationToken)

Check warning on line 372 in TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
// TODO: get this profile list from API

Expand Down Expand Up @@ -482,7 +471,7 @@

private String TestHostApi;

public static Decimal GetAmount(Random r, ContractProduct product = null)

Check warning on line 474 in TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

Cannot convert null literal to non-nullable reference type.
{
return product switch
{
Expand Down Expand Up @@ -762,7 +751,7 @@
return ResultHelpers.CreateFailure(tokenResult);

SerialisedMessage requestSerialisedMessage = request.CreateSerialisedMessage();
SerialisedMessage responseSerialisedMessage = null;

Check warning on line 754 in TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

Converting null literal or possible null value to non-nullable type.

this.WriteTrace($"About to Send sale for Merchant [{merchant.MerchantName}]");
Result<SerialisedMessage> result = new Result<SerialisedMessage>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,22 +164,22 @@ public static async Task<Result> GenerateTransactions(ITransactionDataGeneratorS
}

Random r = new Random();
List<string> results = new List<string>();
List<string> results = new();
foreach (ContractResponse contract in contracts) {
if (config.ContractNames.Contains(contract.Description) == false)
continue;

int numberOfSales = r.Next(2, 4);
// Generate and send some sales
Result saleResult = await t.SendSales(transactionDate, merchant, contract, numberOfSales, cancellationToken);
Result saleResult = await t.SendSales(transactionDate, merchant, contract, numberOfSales, 0,cancellationToken);

if (saleResult.IsFailed) {
results.Add(contract.OperatorName);
}
}

if (results.Any()) {
return Result.Failure($"Error sending sales files for merchant [{merchant.MerchantName}] [{string.Join(",", results)}]");
return Result.Failure($"Error sending sales files for merchant [{merchant.MerchantName}] [{String.Join(",", results)}]");
}

return Result.Success();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,41 @@

public class BaseConfiguration {
public Boolean IsEnabled { get; set; } = true;
public Int32? TaskDelay { get; set; }
}

public class ReplayParkedQueueJobConfiguration : BaseConfiguration
{

}

public class MakeFloatCreditsJobConfiguration : BaseConfiguration
{
public class ReplayParkedQueueJobConfiguration : BaseConfiguration;

public class MakeFloatCreditsJobConfiguration : BaseConfiguration {
public Guid EstateId { get; set; }
public List<DepositAmount> DepositAmounts { get; set; } = new List<DepositAmount>();
}


public class DepositAmount : BaseConfiguration
{
public class DepositAmount : BaseConfiguration {
public Guid ContractId { get; set; }
public Guid ProductId { get; set; }
public Decimal Amount { get; set; }
}

public class UploadTransactionFileJobConfiguration : BaseConfiguration
{
public class UploadTransactionFileJobConfiguration : BaseConfiguration {
public Guid EstateId { get; set; }
public Guid MerchantId { get; set; }
public Guid UserId { get; set; }
public List<String> ContractsToInclude { get; set; }
}
}

public class GenerateTransactionsJobConfiguration : BaseConfiguration
{
public class GenerateTransactionsJobConfiguration : BaseConfiguration {
public Guid EstateId { get; set; }
public Guid MerchantId { get; set; }
}

public class ProcessSettlementJobConfiguration : BaseConfiguration
{
public class ProcessSettlementJobConfiguration : BaseConfiguration {
public Guid EstateId { get; set; }
public Guid MerchantId { get; set; }
}

public class MerchantStatementJobConfiguration : BaseConfiguration
{
public class MerchantStatementJobConfiguration : BaseConfiguration {
public Guid EstateId { get; set; }
public Guid MerchantId { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ public async Task ReplayParkedQueue(TickerFunctionContext<ReplayParkedQueueJobCo
Logger.LogWarning("Replay Parked Queue Job is not enabled");
return;
}

Result result = await Jobs.ReplayParkedQueues(this.BaseConfiguration.EventStoreAddress, ct);

if (result.IsFailed) {
Expand Down Expand Up @@ -203,7 +202,7 @@ public async Task GenerateMerchantTransactions(TickerFunctionContext<GenerateTra
};

Result result = await Jobs.GenerateSaleTransactions(this.TransactionDataGeneratorService, tickerContext.Request.EstateId,
tickerContext.Request.MerchantId, ct);
tickerContext.Request.MerchantId, tickerContext.Request.TaskDelay.GetValueOrDefault(0), ct);
if (result.IsFailed)
{
throw new ApplicationException(result.Message);
Expand Down Expand Up @@ -367,6 +366,7 @@ public static async Task<Result> ReplayParkedQueues(String eventStoreAddress,

public static async Task<Result> GenerateSaleTransactions(ITransactionDataGeneratorService t,
Guid estateId, Guid merchantId,
Int32 timeDelay,
CancellationToken cancellationToken)
{
// get the merchant
Expand Down Expand Up @@ -398,9 +398,9 @@ public static async Task<Result> GenerateSaleTransactions(ITransactionDataGenera
Random r = new Random();
List<string> results = new List<string>();
foreach (ContractResponse contract in contracts) {
int numberOfSales = r.Next(1, 2);
int numberOfSales = r.Next(1, 5);
// Generate and send some sales
Result saleResult = await t.SendSales(transactionDate, merchant, contract, numberOfSales, cancellationToken);
Result saleResult = await t.SendSales(transactionDate, merchant, contract, numberOfSales, timeDelay, cancellationToken);

if (saleResult.IsFailed)
{
Expand Down
Loading