Skip to content

Commit 244881f

Browse files
Merge pull request #129 from TransactionProcessing/task/remove_estatemanagement_from_setup
Enhance transaction processing and configuration updates
2 parents adf3b51 + 965094c commit 244881f

8 files changed

Lines changed: 150 additions & 55 deletions

File tree

Scripts/Sales Reconciliation.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
2+
select CONCAT(YEAR(transactiondate),'-', FORMAT(transactiondate, 'MM')),
3+
count(*) as 'count',
4+
SUM(case [transaction].TransactionType
5+
WHEN 'Logon' THEN 1
6+
ELSE 0 END) as logoncount,
7+
SUM(case [transaction].TransactionType
8+
WHEN 'Sale' THEN 1
9+
ELSE 0 END) as salecount,
10+
SUM(case [transaction].IsCompleted
11+
WHEN 1 THEN 1
12+
ELSE 0 END) as completedcount,
13+
SUM(case [transaction].IsAuthorised
14+
WHEN 1 THEN 1
15+
ELSE 0 END) as authorisedcount,
16+
SUM(case [transaction].IsAuthorised
17+
WHEN 0 THEN 1
18+
ELSE 0 END) as failedcount,
19+
SUM([transaction].TransactionAmount) as totalamount
20+
from [transaction]
21+
group by CONCAT(YEAR(transactiondate),'-', FORMAT(transactiondate, 'MM'))
22+
order by CONCAT(YEAR(transactiondate),'-', FORMAT(transactiondate, 'MM')) asc
23+
24+
25+
fromAll()
26+
.when({
27+
$init: function () {
28+
return {
29+
monthlySales: {}
30+
};
31+
},
32+
33+
TransactionHasStartedEvent: function (state, event) {
34+
const data = event.body;
35+
36+
// Check transactionType
37+
if (data.transactionType !== "Sale" && data.transactionType !== "Logon") {
38+
return state;
39+
}
40+
41+
const monthKey = getMonthKey(data.transactionDateTime);
42+
const monthly = ensureMonthEntry(state, monthKey);
43+
44+
monthly.count += 1;
45+
if (data.transactionType === "Sale") {
46+
monthly.saleCount += 1;
47+
if (typeof data.transactionAmount !== "number") {
48+
monthly.totalAmount += 0;
49+
return state;
50+
}
51+
monthly.totalAmount += data.transactionAmount;
52+
}
53+
54+
if (data.transactionType === "Logon") {
55+
monthly.logonCount += 1;
56+
}
57+
58+
return state;
59+
},
60+
61+
TransactionHasBeenCompletedEvent: function (state, event) {
62+
const data = event.body;
63+
const monthKey = getMonthKey(data.transactionDateTime);
64+
const monthly = ensureMonthEntry(state, monthKey);
65+
66+
monthly.completedCount += 1;
67+
68+
if (data.isAuthorised === true) {
69+
monthly.authorisedcount += 1;
70+
} else {
71+
monthly.failedCount += 1;
72+
}
73+
74+
return state;
75+
}
76+
});
77+
78+
function getMonthKey(dateString) {
79+
const date = new Date(dateString);
80+
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
81+
}
82+
83+
function ensureMonthEntry(state, monthKey) {
84+
if (!state.monthlySales.hasOwnProperty(monthKey)) {
85+
state.monthlySales[monthKey] = {
86+
count: 0,
87+
logonCount: 0,
88+
saleCount: 0,
89+
completedCount: 0,
90+
authorisedcount: 0,
91+
failedCount: 0,
92+
totalAmount: 0,
93+
94+
95+
};
96+
}
97+
98+
return state.monthlySales[monthKey];
99+
}

TransactionProcessing.SchedulerService/DataGenerator/Program.cs

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using SimpleResults;
23
using TransactionProcessing.SchedulerService.DataGenerator;
34
using TransactionProcessor.DataTransferObjects.Responses.Contract;
45
using TransactionProcessor.DataTransferObjects.Responses.Merchant;
@@ -66,7 +67,7 @@ static async Task Main(string[] args){
6667
Guid estateId = Guid.Parse("435613ac-a468-47a3-ac4f-649d89764c22");
6768

6869
// Get a token to talk to the estate service
69-
CancellationToken cancellationToken = new CancellationToken();
70+
CancellationToken cancellationToken = new();
7071
String clientId = "serviceClient";
7172
String clientSecret = "d192cbc46d834d0da90e8a9d50ded543";
7273
ITransactionDataGeneratorService g = new TransactionDataGeneratorService(Program.SecurityServiceClient,
@@ -97,14 +98,25 @@ private static async Task GenerateStatements(ITransactionDataGeneratorService g,
9798

9899
private static async Task GenerateTransactions(ITransactionDataGeneratorService g, Guid estateId, CancellationToken cancellationToken){
99100
// Set the date range
100-
DateTime startDate = new DateTime(2025, 3, 1); //27/7
101-
DateTime endDate = new DateTime(2025, 3,2); // This is the date of the last generated transaction
102-
103-
List<DateTime> dateRange = g.GenerateDateRange(startDate, endDate);
104-
List<ContractResponse> allContracts = await g.GetEstateContracts(estateId, cancellationToken);
105-
List<MerchantResponse> merchants = await g.GetMerchants(estateId, cancellationToken);
106-
107-
Dictionary<(String, String), Decimal> floatDeposits = new Dictionary<(String, String), Decimal> {
101+
DateTime startDate = new DateTime(2025, 4, 14); //27/7
102+
DateTime endDate = new DateTime(2025, 4,30); // This is the date of the last generated transaction
103+
104+
Result<List<DateTime>> dateRangeResult = g.GenerateDateRange(startDate, endDate);
105+
if (dateRangeResult.IsFailed)
106+
{
107+
Console.WriteLine($"Failed to generate date range: {dateRangeResult.Message}");
108+
return;
109+
}
110+
var allContractsResult = await g.GetEstateContracts(estateId, cancellationToken);
111+
if (allContractsResult.IsFailed) {
112+
Console.WriteLine($"Failed to get estate contracts: {allContractsResult.Message}");
113+
}
114+
var merchantsResult = await g.GetMerchants(estateId, cancellationToken);
115+
if (merchantsResult.IsFailed)
116+
{
117+
Console.WriteLine($"Failed to get merchants: {merchantsResult.Message} ");
118+
}
119+
Dictionary<(String, String), Decimal> floatDeposits = new() {
108120
{ ("Healthcare Centre 1 Contract", "10 KES Voucher"), 1400 },
109121
{ ("Healthcare Centre 1 Contract", "Custom"), 27000 },
110122
{ ("Safaricom Contract", "100 KES Topup"), 14000 },
@@ -133,14 +145,14 @@ private static async Task GenerateTransactions(ITransactionDataGeneratorService
133145
// Settlement
134146
DataToSend dataToSend = DataToSend.Settlement;
135147

136-
foreach (DateTime dateTime in dateRange){
148+
foreach (DateTime dateTime in dateRangeResult.Data){
137149

138150
if ((dataToSend & DataToSend.FloatDeposits) == DataToSend.FloatDeposits)
139151
{
140-
foreach (ContractResponse contractResponse in allContracts) {
152+
foreach (ContractResponse contractResponse in allContractsResult.Data) {
141153
foreach (ContractProduct contractResponseProduct in contractResponse.Products) {
142154
// Lookup the deposit amount here
143-
var depositAmount = floatDeposits.SingleOrDefault(f =>
155+
KeyValuePair<(String, String), Decimal> depositAmount = floatDeposits.SingleOrDefault(f =>
144156
f.Key.Item1 == contractResponse.Description &&
145157
f.Key.Item2 == contractResponseProduct.Name);
146158

@@ -151,7 +163,7 @@ await g.MakeFloatDeposit(dateTime, estateId, contractResponse.ContractId,
151163
}
152164

153165
if ((dataToSend & DataToSend.Logons) == DataToSend.Logons) {
154-
foreach (MerchantResponse merchant in merchants) {
166+
foreach (MerchantResponse merchant in merchantsResult.Data) {
155167

156168
// Send a logon transaction
157169
await g.PerformMerchantLogon(dateTime, merchant, cancellationToken);
@@ -160,7 +172,7 @@ await g.MakeFloatDeposit(dateTime, estateId, contractResponse.ContractId,
160172

161173
if ((dataToSend & DataToSend.Sales) == DataToSend.Sales)
162174
{
163-
foreach (MerchantResponse merchant in merchants) {
175+
foreach (MerchantResponse merchant in merchantsResult.Data) {
164176
// Get the merchants contracts
165177
List<ContractResponse> contracts = await g.GetMerchantContracts(merchant, cancellationToken);
166178
foreach (ContractResponse contract in contracts) {
@@ -173,7 +185,7 @@ await g.MakeFloatDeposit(dateTime, estateId, contractResponse.ContractId,
173185
}
174186

175187
if ((dataToSend & DataToSend.Files) == DataToSend.Files) {
176-
foreach (MerchantResponse merchant in merchants) {
188+
foreach (MerchantResponse merchant in merchantsResult.Data) {
177189
// Get the merchants contracts
178190
List<ContractResponse> contracts = await g.GetMerchantContracts(merchant, cancellationToken);
179191

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ public static DateTime GetTransactionDateTime(Random r, DateTime dateTime)
830830
else
831831
{
832832
// Generate the time
833-
Int32 hours = r.Next(0, 23);
833+
Int32 hours = r.Next(9, 22);
834834
Int32 minutes = r.Next(0, 59);
835835
Int32 seconds = r.Next(0, 59);
836836

TransactionProcessor.SystemSetupTool/EstateSetupFunctions.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,11 +449,16 @@ private async Task<Result> UpdateMerchant(Merchant merchant,
449449
return ResultHelpers.CreateFailure(getContractsResult);
450450

451451
var merchantContractsResult = await this.TransactionProcessorClient.GetMerchantContracts(this.TokenResponse.AccessToken, this.EstateId, existingMerchant.MerchantId, cancellationToken);
452-
if (merchantContractsResult.IsFailed)
452+
if (merchantContractsResult.IsFailed && merchantContractsResult.Status != ResultStatus.NotFound)
453453
return ResultHelpers.CreateFailure(merchantContractsResult);
454+
List<ContractResponse> merchantContracts = merchantContractsResult.Data;
455+
if (merchantContractsResult.Status == ResultStatus.NotFound) {
456+
merchantContracts = new List<ContractResponse>();
457+
}
458+
454459
// Now contracts
455-
foreach (ContractResponse contractResponse in getContractsResult.Data) {
456-
if (merchantContractsResult.Data.SingleOrDefault(c => c.ContractId == contractResponse.ContractId) != null)
460+
foreach (ContractResponse contractResponse in getContractsResult.Data) {
461+
if (merchantContracts.SingleOrDefault(c => c.ContractId == contractResponse.ContractId) != null)
457462
continue;
458463

459464
AddMerchantContractRequest addMerchantContractRequest = new() { ContractId = contractResponse.ContractId };

TransactionProcessor.SystemSetupTool/EventStoreFunctions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ private async Task<Result> SetupSubscriptions(CancellationToken cancellationToke
4545
("$ce-FileImportLogAggregate", "Transaction Processor", 0),
4646
("$ce-OperatorAggregate", "Transaction Processor", 0),
4747

48+
("$ce-TransactionAggregate", "Transaction Processor - Domain", 0),
49+
("$ce-SettlementAggregate", "Transaction Processor - Domain", 0),
50+
("$ce-FloatAggregate", "Transaction Processor - Domain", 0),
51+
("$ce-MerchantStatementForDateAggregate", "Transaction Processor - Domain", 0),
52+
4853
("$ce-EstateAggregate", "Transaction Processor - Ordered", 1),
4954
("$ce-SettlementAggregate", "Transaction Processor - Ordered", 1),
5055
("$ce-VoucherAggregate", "Transaction Processor - Ordered", 1),

TransactionProcessor.SystemSetupTool/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ static async Task Main(string[] args) {
6969

7070
Mode setupMode = Mode.EstateSetup;
7171

72-
String configFileName = "setupconfig.json";
72+
String configFileName = "setupconfig.staging.json";
7373

7474
IdentityServerConfiguration identityServerConfiguration = await Program.GetIdentityServerConfig(cancellationToken);
7575
IdentityServerFunctions identityServerFunctions = new(Program.SecurityServiceClient, identityServerConfiguration);

TransactionProcessor.SystemSetupTool/appsettings.json

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
{
22
"AppSettings": {
33
// Local (Docker)
4-
//"EstateManagementUri": "http://127.0.0.1:5000",
5-
"SecurityServiceUri": "https://127.0.0.1:5001",
6-
"TransactionProcessorApi": "http://127.0.0.1:5002",
7-
"EventStoreAddress": "esdb://admin:changeit@127.0.0.1:4113?tls=false&tlsVerifyCert=false"
4+
//"SecurityServiceUri": "https://127.0.0.1:5001",
5+
//"TransactionProcessorApi": "http://127.0.0.1:5002",
6+
//"EventStoreAddress": "esdb://admin:changeit@127.0.0.1:4113?tls=false&tlsVerifyCert=false"
87

98
// Staging
10-
//"EstateManagementUri": "http://192.168.1.167:5000",
11-
//"SecurityServiceUri": "https://192.168.1.167:5001",
12-
//"TransactionProcessorApi": "http://192.168.1.167:5002",
13-
//"EventStoreAddress": "esdb://admin:changeit@192.168.1.167:2113?tls=false&tlsVerifyCert=false"
9+
"SecurityServiceUri": "https://192.168.1.167:5001",
10+
"TransactionProcessorApi": "http://192.168.1.167:5002",
11+
"EventStoreAddress": "esdb://admin:changeit@192.168.1.167:2113?tls=false&tlsVerifyCert=false"
1412
//"EventStoreAddress": "esdb://admin:changeit@192.168.1.157:2113?tls=false&tlsVerifyCert=false"
1513

1614
// Production
17-
//"EstateManagementUri": "http://192.168.1.155:5000",
1815
//"SecurityServiceUri": "https://192.168.1.155:5001",
1916
//"TransactionProcessorApi": "http://192.168.1.155:5002",
2017
//"EventStoreAddress": "esdb://admin:changeit@192.168.1.155:2113?tls=false&tlsVerifyCert=false"

TransactionProcessor.SystemSetupTool/identityserverconfig.json

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,6 @@
4848
}
4949
],
5050
"apiresources": [
51-
{
52-
"secret": "eb47603986574b3ea2e6195a2076696e",
53-
"name": "estateManagement",
54-
"display_name": "Estate Management REST",
55-
"description": "API Resource representing Estate Management REST",
56-
"scopes": [ "estateManagement" ],
57-
"user_claims": [ "merchantId", "estateId", "role" ]
58-
},
5951
{
6052
"secret": "3241913328414df4b8d031ed8f59d1bb",
6153
"name": "estateReporting",
@@ -78,7 +70,7 @@
7870
"display_name": "Transaction Processor REST",
7971
"description": "API Resource representing Transaction Processor REST",
8072
"scopes": [ "transactionProcessor" ],
81-
"user_claims": null
73+
"user_claims": [ "merchantId", "estateId", "role" ]
8274
},
8375
{
8476
"secret": "bc7c25e9bf1649cc9d41abebfe98955e",
@@ -103,15 +95,15 @@
10395
"secret": "d192cbc46d834d0da90e8a9d50ded543",
10496
"client_name": "Service Client",
10597
"client_description": "Client for use in inter service communications",
106-
"allowed_scopes": [ "transactionProcessorACL", "transactionProcessor", "estateManagement", "estateReporting", "messagingService", "fileProcessor" ],
98+
"allowed_scopes": [ "transactionProcessorACL", "transactionProcessor", "estateReporting", "messagingService", "fileProcessor" ],
10799
"allowed_grant_types": [ "client_credentials" ]
108100
},
109101
{
110102
"client_id": "managementUIClient",
111103
"secret": "d192cbc46d834d0da90e8a9d50ded543",
112104
"client_name": "Management UI App Client",
113105
"client_description": "Client for use by management app",
114-
"allowed_scopes": [ "fileProcessor", "estateManagement", "transactionProcessor", "openid", "email", "profile" ],
106+
"allowed_scopes": [ "fileProcessor", "transactionProcessor", "openid", "email", "profile" ],
115107
"allowed_grant_types": [
116108
"hybrid",
117109
"password"
@@ -129,16 +121,6 @@
129121
"require_consent": true,
130122
"allow_offline_access": true
131123
},
132-
{
133-
"client_id": "voucherAppClient",
134-
"secret": "d09bdc23b50f4582aca09134268d5600",
135-
"client_name": "Voucher Mobile App Client",
136-
"client_description": "Client for use by voucher redemption mobile app to process voucher redemptions",
137-
"allowed_scopes": [ "voucherManagementACL" ],
138-
"allowed_grant_types": [
139-
"password"
140-
]
141-
},
142124
{
143125
"client_id": "mobileAppClient",
144126
"secret": "d192cbc46d834d0da90e8a9d50ded543",
@@ -151,11 +133,6 @@
151133
}
152134
],
153135
"apiscopes": [
154-
{
155-
"description": "Scope for Estate Management REST",
156-
"displayName": "Estate Management REST",
157-
"name": "estateManagement"
158-
},
159136
{
160137
"description": "Scope for Estate Reporting REST",
161138
"displayName": "Estate Reporting REST",

0 commit comments

Comments
 (0)