Skip to content

Commit 2a540ef

Browse files
Merge pull request #143 from TransactionProcessing/task/scheduled_job_logic_changes
Add timeDelay parameter to SendSales method
2 parents cf15a59 + b8ee356 commit 2a540ef

File tree

6 files changed

+61
-82
lines changed

6 files changed

+61
-82
lines changed

TransactionProcessing.SchedulerService/DataGenerator/Program.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,8 @@ await g.MakeFloatDeposit(dateTime, estateId, contractResponse.ContractId,
193193
foreach (ContractResponse contract in getMerchantContractsResult.Data) {
194194
// Generate and send some sales
195195

196-
await g.SendSales(dateTime, merchant, contract, 0, cancellationToken);
196+
await g.SendSales(dateTime, merchant, contract, 0,0, cancellationToken);
197197
}
198-
199198
}
200199
}
201200

TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/ITransactionDataGeneratorService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Task<Result> PerformMerchantSettlement(DateTime dateTime,
2222
Guid estateId,
2323
Guid merchantId,
2424
CancellationToken cancellationToken);
25-
Task<Result> SendSales(DateTime dateTime, MerchantResponse merchant, ContractResponse contract, Int32 numberOfSales, CancellationToken cancellationToken);
25+
Task<Result> SendSales(DateTime dateTime, MerchantResponse merchant, ContractResponse contract, Int32 numberOfSales, Int32 timeDelay, CancellationToken cancellationToken);
2626
Task<Result> SendUploadFile(DateTime dateTime, ContractResponse contract, MerchantResponse merchant, Guid userId, CancellationToken cancellationToken);
2727
Task<Result<MerchantResponse>> GetMerchant(Guid estateId, Guid merchantId, CancellationToken cancellationToken);
2828
Task<Result> GenerateMerchantStatement(Guid estateId, Guid merchantId, DateTime statementDateTime, CancellationToken cancellationToken);

TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs

Lines changed: 43 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
using System.Net.Http.Headers;
2-
using System.Text;
3-
using Newtonsoft.Json;
1+
using Newtonsoft.Json;
42
using Polly;
53
using SecurityService.Client;
64
using SecurityService.DataTransferObjects.Responses;
75
using Shared.Results;
86
using SimpleResults;
7+
using System;
8+
using System.Net.Http.Headers;
9+
using System.Text;
910
using TransactionProcessor.Client;
1011
using TransactionProcessor.DataTransferObjects;
1112
using TransactionProcessor.DataTransferObjects.Requests.Merchant;
@@ -201,62 +202,55 @@ public async Task<Result> SendSales(DateTime dateTime,
201202
MerchantResponse merchant,
202203
ContractResponse contract,
203204
Int32 numberOfSales,
205+
Int32 timeDelay,
204206
CancellationToken cancellationToken) {
205207
List<SaleTransactionRequest> salesToSend = new List<SaleTransactionRequest>();
206208
Decimal depositAmount = 0;
207209
(Int32 accountNumber, String accountName, Decimal balance) billDetails = default;
208210
(Int32 meterNumber, String customerName, Decimal amount) meterDetails = default;
209211

210-
foreach (ContractProduct contractProduct in contract.Products)
211-
{
212-
this.WriteTrace($"product [{contractProduct.DisplayText}]");
213-
214-
List<(SaleTransactionRequest request, Decimal amount)> saleRequests = null;
215-
// Get a number of sales to be sent
216-
if (numberOfSales == 0)
217-
{
218-
numberOfSales = this.r.Next(2, 10);
219-
}
212+
// Step 2: Decide how many total transactions to generate in this run
213+
numberOfSales = this.r.Next(1, 6); // e.g. 1–5 transactions per run
214+
List<(SaleTransactionRequest request, Decimal amount)> saleRequests = null;
215+
for (int i = 0; i < numberOfSales; i++) {
216+
ContractProduct? contractProduct = contract.Products[this.r.Next(contract.Products.Count)];
220217

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

225-
if (productSubType == ProductSubType.BillPaymentPostPay)
226-
{
227-
// Create a bill for this sale
228-
billDetails = await this.CreateBillPaymentBill(contract.OperatorName, contractProduct, cancellationToken);
229-
}
221+
await Task.Delay(delayMs);
222+
ProductSubType productSubType = this.GetProductSubType(contract.OperatorName);
230223

231-
if (productSubType == ProductSubType.BillPaymentPrePay)
232-
{
233-
// Create a meter
234-
meterDetails = await this.CreateBillPaymentMeter(contract.OperatorName, contractProduct, cancellationToken);
235-
}
224+
if (productSubType == ProductSubType.BillPaymentPostPay) {
225+
// Create a bill for this sale
226+
billDetails = await this.CreateBillPaymentBill(contract.OperatorName, contractProduct, cancellationToken);
227+
}
236228

237-
saleRequests = productSubType switch
238-
{
239-
ProductSubType.MobileTopup => this.BuildMobileTopupSaleRequests(dateTime, merchant, contract, contractProduct),
240-
ProductSubType.Voucher => this.BuildVoucherSaleRequests(dateTime, merchant, contract, contractProduct),
241-
ProductSubType.BillPaymentPostPay => this.BuildPataPawaPostPayBillPaymentSaleRequests(dateTime, merchant, contract, contractProduct, billDetails),
242-
ProductSubType.BillPaymentPrePay => this.BuildPataPawaPrePayBillPaymentSaleRequests(dateTime, merchant, contract, contractProduct, meterDetails),
243-
_ => throw new Exception($"Product Sub Type [{productSubType}] not yet supported")
244-
};
229+
if (productSubType == ProductSubType.BillPaymentPrePay) {
230+
// Create a meter
231+
meterDetails = await this.CreateBillPaymentMeter(contract.OperatorName, contractProduct, cancellationToken);
232+
}
245233

246-
// Add the value of the sale to the deposit amount
247-
Boolean addToDeposit = i switch
248-
{
249-
_ when i == numberOfSales => false,
250-
_ => true
251-
};
234+
saleRequests = productSubType switch {
235+
ProductSubType.MobileTopup => this.BuildMobileTopupSaleRequests(dateTime, merchant, contract, contractProduct),
236+
ProductSubType.Voucher => this.BuildVoucherSaleRequests(dateTime, merchant, contract, contractProduct),
237+
ProductSubType.BillPaymentPostPay => this.BuildPataPawaPostPayBillPaymentSaleRequests(dateTime, merchant, contract, contractProduct, billDetails),
238+
ProductSubType.BillPaymentPrePay => this.BuildPataPawaPrePayBillPaymentSaleRequests(dateTime, merchant, contract, contractProduct, meterDetails),
239+
_ => throw new Exception($"Product Sub Type [{productSubType}] not yet supported")
240+
};
252241

253-
if (addToDeposit)
254-
{
255-
depositAmount += saleRequests.Sum(sr => sr.amount);
256-
}
242+
// Add the value of the sale to the deposit amount
243+
Boolean addToDeposit = i switch {
244+
_ when i == numberOfSales => false,
245+
_ => true
246+
};
257247

258-
salesToSend.AddRange(saleRequests.Select(s => s.request));
248+
if (addToDeposit) {
249+
depositAmount += saleRequests.Sum(sr => sr.amount);
259250
}
251+
252+
salesToSend.AddRange(saleRequests.Select(s => s.request));
253+
260254
}
261255

262256
// Build up a deposit (minus the last sale amount)
@@ -274,24 +268,19 @@ public async Task<Result> SendSales(DateTime dateTime,
274268
Int32 salesSent = 0;
275269
IOrderedEnumerable<SaleTransactionRequest> orderedSales = salesToSend.OrderBy(s => s.TransactionDateTime);
276270
// Send the sales to the host
277-
foreach (SaleTransactionRequest sale in orderedSales)
278-
{
271+
foreach (SaleTransactionRequest sale in orderedSales) {
279272
sale.TransactionNumber = this.GetTransactionNumber().ToString();
280273
Result<SerialisedMessage> saleResult = await this.SendSaleTransaction(merchant, sale, cancellationToken);
281-
if (saleResult.IsSuccess)
282-
{
274+
if (saleResult.IsSuccess) {
283275
salesSent++;
284276
}
285-
//var random = new Random();
286-
//int delaySeconds = random.Next(5, 10); // 30–60 inclusive
287-
//await Task.Delay(TimeSpan.FromSeconds(delaySeconds), cancellationToken);
288277
}
289278

290-
if (salesSent == 0)
291-
{
279+
if (salesSent == 0) {
292280
// All sales failed
293281
return Result.Failure("All sales have failed");
294282
}
283+
295284
this.WriteTraceX($"{salesSent} sales for merchant {merchant.MerchantName} sent to host {orderedSales.Count() - salesSent} sales failed to send");
296285
return Result.Success();
297286
}

TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Jobs/Jobs.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,22 +164,22 @@ public static async Task<Result> GenerateTransactions(ITransactionDataGeneratorS
164164
}
165165

166166
Random r = new Random();
167-
List<string> results = new List<string>();
167+
List<string> results = new();
168168
foreach (ContractResponse contract in contracts) {
169169
if (config.ContractNames.Contains(contract.Description) == false)
170170
continue;
171171

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

176176
if (saleResult.IsFailed) {
177177
results.Add(contract.OperatorName);
178178
}
179179
}
180180

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

185185
return Result.Success();

TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.TickerQ/Configuration/BaseConfiguration.cs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,50 +10,41 @@
1010

1111
public class BaseConfiguration {
1212
public Boolean IsEnabled { get; set; } = true;
13+
public Int32? TaskDelay { get; set; }
1314
}
1415

15-
public class ReplayParkedQueueJobConfiguration : BaseConfiguration
16-
{
17-
18-
}
19-
20-
public class MakeFloatCreditsJobConfiguration : BaseConfiguration
21-
{
16+
public class ReplayParkedQueueJobConfiguration : BaseConfiguration;
2217

18+
public class MakeFloatCreditsJobConfiguration : BaseConfiguration {
2319
public Guid EstateId { get; set; }
2420
public List<DepositAmount> DepositAmounts { get; set; } = new List<DepositAmount>();
2521
}
2622

2723

28-
public class DepositAmount : BaseConfiguration
29-
{
24+
public class DepositAmount : BaseConfiguration {
3025
public Guid ContractId { get; set; }
3126
public Guid ProductId { get; set; }
3227
public Decimal Amount { get; set; }
3328
}
3429

35-
public class UploadTransactionFileJobConfiguration : BaseConfiguration
36-
{
30+
public class UploadTransactionFileJobConfiguration : BaseConfiguration {
3731
public Guid EstateId { get; set; }
3832
public Guid MerchantId { get; set; }
3933
public Guid UserId { get; set; }
4034
public List<String> ContractsToInclude { get; set; }
41-
}
35+
}
4236

43-
public class GenerateTransactionsJobConfiguration : BaseConfiguration
44-
{
37+
public class GenerateTransactionsJobConfiguration : BaseConfiguration {
4538
public Guid EstateId { get; set; }
4639
public Guid MerchantId { get; set; }
4740
}
4841

49-
public class ProcessSettlementJobConfiguration : BaseConfiguration
50-
{
42+
public class ProcessSettlementJobConfiguration : BaseConfiguration {
5143
public Guid EstateId { get; set; }
5244
public Guid MerchantId { get; set; }
5345
}
5446

55-
public class MerchantStatementJobConfiguration : BaseConfiguration
56-
{
47+
public class MerchantStatementJobConfiguration : BaseConfiguration {
5748
public Guid EstateId { get; set; }
5849
public Guid MerchantId { get; set; }
5950
}

TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.TickerQ/Jobs/Jobs.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ public async Task ReplayParkedQueue(TickerFunctionContext<ReplayParkedQueueJobCo
107107
Logger.LogWarning("Replay Parked Queue Job is not enabled");
108108
return;
109109
}
110-
111110
Result result = await Jobs.ReplayParkedQueues(this.BaseConfiguration.EventStoreAddress, ct);
112111

113112
if (result.IsFailed) {
@@ -203,7 +202,7 @@ public async Task GenerateMerchantTransactions(TickerFunctionContext<GenerateTra
203202
};
204203

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

368367
public static async Task<Result> GenerateSaleTransactions(ITransactionDataGeneratorService t,
369368
Guid estateId, Guid merchantId,
369+
Int32 timeDelay,
370370
CancellationToken cancellationToken)
371371
{
372372
// get the merchant
@@ -398,9 +398,9 @@ public static async Task<Result> GenerateSaleTransactions(ITransactionDataGenera
398398
Random r = new Random();
399399
List<string> results = new List<string>();
400400
foreach (ContractResponse contract in contracts) {
401-
int numberOfSales = r.Next(1, 2);
401+
int numberOfSales = r.Next(1, 5);
402402
// Generate and send some sales
403-
Result saleResult = await t.SendSales(transactionDate, merchant, contract, numberOfSales, cancellationToken);
403+
Result saleResult = await t.SendSales(transactionDate, merchant, contract, numberOfSales, timeDelay, cancellationToken);
404404

405405
if (saleResult.IsFailed)
406406
{

0 commit comments

Comments
 (0)