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
3 changes: 2 additions & 1 deletion EstateManagementUI.BlazorServer/Components/App.razor
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
<body class="h-full">
<Routes />
<ReconnectModal />
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js" integrity="sha384-9nhczxUqK87bcKHh20fSQcTGD4qq5GhayNYSYWqwBkINBhOfQLg/P5HG5lF1urn4" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js" integrity="sha384-9nhczxUqK87bcKHh20fSQcTGD4qq5GhOfQLg/P5HG5lF1urn4" crossorigin="anonymous"></script>
<script src="js/charts.js"></script>
<script src="js/site.js"></script>
<script src="@Assets["_framework/blazor.web.js"]"></script>
</body>

Expand Down

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions EstateManagementUI.BlazorServer/Models/Models.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,22 @@ public class SettlementSummaryModel
public decimal NetSettlementAmount { get; set; }
public string? SettlementStatus { get; set; }
}

// Transaction Detail Models
public class TransactionDetailModel
{
public Guid TransactionId { get; set; }
public DateTime TransactionDateTime { get; set; }
public string? MerchantName { get; set; }
public Guid MerchantId { get; set; }
public string? OperatorName { get; set; }
public Guid OperatorId { get; set; }
public string? ProductName { get; set; }
public Guid ProductId { get; set; }
public string? TransactionType { get; set; } // sale, refund, reversal
public string? TransactionStatus { get; set; } // successful, failed, reversed
public decimal GrossAmount { get; set; }
public decimal FeesCommission { get; set; }
public decimal NetAmount { get; set; }
public string? SettlementReference { get; set; }
}
1 change: 1 addition & 0 deletions EstateManagementUI.BlazorServer/Requests/Requests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public record GetProductPerformanceQuery(CorrelationId CorrelationId, string Acc
public record GetOperatorTransactionSummaryQuery(CorrelationId CorrelationId, string AccessToken, Guid EstateId, DateTime StartDate, DateTime EndDate, Guid? MerchantId = null, Guid? OperatorId = null) : IRequest<Result<List<OperatorTransactionSummaryModel>>>;
public record GetMerchantSettlementHistoryQuery(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid? MerchantId, DateTime StartDate, DateTime EndDate) : IRequest<Result<List<MerchantSettlementHistoryModel>>>;
public record GetSettlementSummaryQuery(CorrelationId CorrelationId, string AccessToken, Guid EstateId, DateTime StartDate, DateTime EndDate, Guid? MerchantId = null, string? Status = null) : IRequest<Result<List<SettlementSummaryModel>>>;
public record GetTransactionDetailQuery(CorrelationId CorrelationId, string AccessToken, Guid EstateId, DateTime StartDate, DateTime EndDate, Guid? MerchantId = null, Guid? OperatorId = null, Guid? ProductId = null) : IRequest<Result<List<TransactionDetailModel>>>;
}

public static class Commands
Expand Down
114 changes: 114 additions & 0 deletions EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
Queries.GetTopOperatorDataQuery => Task.FromResult((TResponse)(object)Result<List<TopBottomOperatorDataModel>>.Success(GetMockTopOperators())),
Queries.GetBottomOperatorDataQuery => Task.FromResult((TResponse)(object)Result<List<TopBottomOperatorDataModel>>.Success(GetMockBottomOperators())),
Queries.GetLastSettlementQuery => Task.FromResult((TResponse)(object)Result<LastSettlementModel>.Success(GetMockLastSettlement())),
Queries.GetTransactionDetailQuery q => Task.FromResult((TResponse)(object)Result<List<TransactionDetailModel>>.Success(GetMockTransactionDetails(q))),

// Commands - just return success
Commands.AddMerchantDeviceCommand => Task.FromResult((TResponse)(object)Result.Success()),
Expand Down Expand Up @@ -431,4 +432,117 @@
SalesValue = 125000.00m,
SettlementValue = 123750.00m
};

private static List<TransactionDetailModel> GetMockTransactionDetails(Queries.GetTransactionDetailQuery query)

Check warning on line 436 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L436

Method StubbedMediatorService::GetMockTransactionDetails has 87 lines of code (limit is 50)

Check warning on line 436 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L436

Method StubbedMediatorService::GetMockTransactionDetails has a cyclomatic complexity of 12 (limit is 8)
{
var merchants = GetMockMerchants();
var operators = GetMockOperators();
var contracts = GetMockContracts();

// Get all products with their IDs from contracts
var productList = contracts
.SelectMany(c => c.Products ?? new List<ContractProductModel>())
.Where(p => !string.IsNullOrEmpty(p.ProductName))
.ToList();

var transactionTypes = new[] { "Sale", "Refund", "Reversal" };

Check warning on line 448 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L448

Remove the unused local variable 'transactionTypes'.
var transactionStatuses = new[] { "Successful", "Failed", "Reversed" };

Check warning on line 449 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L449

Define a constant instead of using this literal 'Successful' 4 times.

Check warning on line 449 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L449

Remove the unused local variable 'transactionStatuses'.

var random = new Random(42); // Use seed for consistent data
var transactions = new List<TransactionDetailModel>();

// Calculate days in date range
var daysInRange = (query.EndDate - query.StartDate).Days + 1;
var transactionsPerDay = 50;
var totalTransactions = daysInRange * transactionsPerDay;

for (int i = 0; i < totalTransactions; i++)
{
// Random date within range
var randomDays = random.Next(0, daysInRange);

Check failure on line 462 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L462

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var randomHours = random.Next(0, 24);

Check failure on line 463 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L463

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var randomMinutes = random.Next(0, 60);

Check failure on line 464 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L464

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var transactionDate = query.StartDate.AddDays(randomDays)
.AddHours(randomHours)
.AddMinutes(randomMinutes);

// Random merchant, operator, and product
var merchant = merchants[random.Next(merchants.Count)];

Check failure on line 470 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L470

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var op = operators[random.Next(operators.Count)];

Check failure on line 471 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L471

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var product = productList[random.Next(productList.Count)];

Check failure on line 472 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L472

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.

// Random type and status (90% successful sales)
var typeRoll = random.NextDouble();

Check failure on line 475 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L475

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var statusRoll = random.NextDouble();

Check failure on line 476 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L476

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.

string transactionType;
string transactionStatus;

if (typeRoll < 0.85)
{
transactionType = "Sale";
transactionStatus = statusRoll < 0.95 ? "Successful" : "Failed";
}
else if (typeRoll < 0.95)
{
transactionType = "Refund";
transactionStatus = "Successful";
}
else
{
transactionType = "Reversal";
transactionStatus = "Reversed";
}

// Random amounts
var grossAmount = Math.Round((decimal)(random.NextDouble() * 200 + 10), 2);

Check failure on line 498 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L498

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var feePercentage = 0.015m; // 1.5%
var feesCommission = Math.Round(grossAmount * feePercentage, 2);
var netAmount = grossAmount - feesCommission;

// Settlement reference (70% have one for successful transactions)
string? settlementReference = null;
if (transactionStatus == "Successful" && random.NextDouble() < 0.7)
{
settlementReference = $"STL-{transactionDate:yyyyMMdd}-{random.Next(1000, 9999)}";

Check failure on line 507 in EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/StubbedMediatorService.cs#L507

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
}

transactions.Add(new TransactionDetailModel
{
TransactionId = Guid.NewGuid(),
TransactionDateTime = transactionDate,
MerchantName = merchant.MerchantName,
MerchantId = merchant.MerchantId,
OperatorName = op.Name,
OperatorId = op.OperatorId,
ProductName = product.ProductName,
ProductId = product.ContractProductId,
TransactionType = transactionType,
TransactionStatus = transactionStatus,
GrossAmount = grossAmount,
FeesCommission = feesCommission,
NetAmount = netAmount,
SettlementReference = settlementReference
});
}

// Apply filters
if (query.MerchantId.HasValue)
{
transactions = transactions.Where(t => t.MerchantId == query.MerchantId.Value).ToList();
}

if (query.OperatorId.HasValue)
{
transactions = transactions.Where(t => t.OperatorId == query.OperatorId.Value).ToList();
}

if (query.ProductId.HasValue)
{
transactions = transactions.Where(t => t.ProductId == query.ProductId.Value).ToList();
}

// Sort by transaction date descending (most recent first)
return transactions.OrderByDescending(t => t.TransactionDateTime).ToList();
}
}
111 changes: 111 additions & 0 deletions EstateManagementUI.BlazorServer/Services/TestMediatorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
Queries.GetOperatorTransactionSummaryQuery query => Task.FromResult((TResponse)(object)Result<List<OperatorTransactionSummaryModel>>.Success(GetMockOperatorTransactionSummary(query))),
Queries.GetMerchantSettlementHistoryQuery query => Task.FromResult((TResponse)(object)Result<List<MerchantSettlementHistoryModel>>.Success(GetMockMerchantSettlementHistory(query))),
Queries.GetSettlementSummaryQuery query => Task.FromResult((TResponse)(object)Result<List<SettlementSummaryModel>>.Success(GetMockSettlementSummary(query))),
Queries.GetTransactionDetailQuery q => Task.FromResult((TResponse)(object)Result<List<TransactionDetailModel>>.Success(GetMockTransactionDetails(q))),

// Commands - execute against test data store
Commands.CreateMerchantCommand cmd => Task.FromResult((TResponse)(object)ExecuteCreateMerchant(cmd)),
Expand Down Expand Up @@ -819,4 +820,114 @@

return summary;
}

private List<TransactionDetailModel> GetMockTransactionDetails(Queries.GetTransactionDetailQuery query)

Check warning on line 824 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L824

Method TestMediatorService::GetMockTransactionDetails has 85 lines of code (limit is 50)

Check warning on line 824 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L824

Method TestMediatorService::GetMockTransactionDetails has a cyclomatic complexity of 17 (limit is 8)
{
var merchants = _testDataStore.GetMerchants(query.EstateId);
var operators = _testDataStore.GetOperators(query.EstateId);
var contracts = _testDataStore.GetContracts(query.EstateId);

// Get all products with their IDs from contracts
var productList = contracts
.SelectMany(c => c.Products ?? new List<ContractProductModel>())
.Where(p => !string.IsNullOrEmpty(p.ProductName))
.ToList();

var random = new Random(42); // Use seed for consistent data
var transactions = new List<TransactionDetailModel>();

// Calculate days in date range
var daysInRange = (query.EndDate - query.StartDate).Days + 1;
var transactionsPerDay = 50;
var totalTransactions = daysInRange * transactionsPerDay;

for (int i = 0; i < totalTransactions; i++)
{
// Random date within range
var randomDays = random.Next(0, daysInRange);

Check failure on line 847 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L847

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var randomHours = random.Next(0, 24);

Check failure on line 848 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L848

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var randomMinutes = random.Next(0, 60);

Check failure on line 849 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L849

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var transactionDate = query.StartDate.AddDays(randomDays)
.AddHours(randomHours)
.AddMinutes(randomMinutes);

// Random merchant, operator, and product
var merchant = merchants[random.Next(merchants.Count)];

Check failure on line 855 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L855

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var op = operators[random.Next(operators.Count)];

Check failure on line 856 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L856

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var product = productList.Count > 0 ? productList[random.Next(productList.Count)] : null;

Check failure on line 857 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L857

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.

// Random type and status (90% successful sales)
var typeRoll = random.NextDouble();

Check failure on line 860 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L860

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var statusRoll = random.NextDouble();

Check failure on line 861 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L861

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.

string transactionType;
string transactionStatus;

if (typeRoll < 0.85)
{
transactionType = "Sale";
transactionStatus = statusRoll < 0.95 ? "Successful" : "Failed";
}
else if (typeRoll < 0.95)
{
transactionType = "Refund";
transactionStatus = "Successful";
}
else
{
transactionType = "Reversal";
transactionStatus = "Reversed";
}

// Random amounts
var grossAmount = Math.Round((decimal)(random.NextDouble() * 200 + 10), 2);

Check failure on line 883 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L883

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
var feePercentage = 0.015m; // 1.5%
var feesCommission = Math.Round(grossAmount * feePercentage, 2);
var netAmount = grossAmount - feesCommission;

// Settlement reference (70% have one for successful transactions)
string? settlementReference = null;
if (transactionStatus == "Successful" && random.NextDouble() < 0.7)
{
settlementReference = $"STL-{transactionDate:yyyyMMdd}-{random.Next(1000, 9999)}";

Check failure on line 892 in EstateManagementUI.BlazorServer/Services/TestMediatorService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/Services/TestMediatorService.cs#L892

Depending on the context, generating weak random numbers may expose cryptographic functions which rely on these numbers to be exploitable.
}

transactions.Add(new TransactionDetailModel
{
TransactionId = Guid.NewGuid(),
TransactionDateTime = transactionDate,
MerchantName = merchant.MerchantName,
MerchantId = merchant.MerchantId,
OperatorName = op.Name,
OperatorId = op.OperatorId,
ProductName = product?.ProductName ?? "Default Product",
ProductId = product?.ContractProductId ?? Guid.Empty,
TransactionType = transactionType,
TransactionStatus = transactionStatus,
GrossAmount = grossAmount,
FeesCommission = feesCommission,
NetAmount = netAmount,
SettlementReference = settlementReference
});
}

// Apply filters
if (query.MerchantId.HasValue)
{
transactions = transactions.Where(t => t.MerchantId == query.MerchantId.Value).ToList();
}

if (query.OperatorId.HasValue)
{
transactions = transactions.Where(t => t.OperatorId == query.OperatorId.Value).ToList();
}

if (query.ProductId.HasValue)
{
transactions = transactions.Where(t => t.ProductId == query.ProductId.Value).ToList();
}

// Sort by transaction date descending (most recent first)
return transactions.OrderByDescending(t => t.TransactionDateTime).ToList();
}
}
8 changes: 8 additions & 0 deletions EstateManagementUI.BlazorServer/Styles/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@
@apply bg-blue-100 text-blue-800;
}

.badge-secondary {
@apply bg-gray-100 text-gray-800;
}

.badge-success {
@apply bg-green-100 text-green-800;
}
Expand All @@ -193,6 +197,10 @@
.badge-info {
@apply bg-teal-100 text-teal-800;
}

.badge-default {
@apply bg-gray-100 text-gray-600;
}
}

/* Base styles */
Expand Down
17 changes: 17 additions & 0 deletions EstateManagementUI.BlazorServer/wwwroot/js/site.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// File download utility
function downloadFile(filename, base64Content) {

Check warning on line 2 in EstateManagementUI.BlazorServer/wwwroot/js/site.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/wwwroot/js/site.js#L2

'downloadFile' is defined but never used.

Check warning on line 2 in EstateManagementUI.BlazorServer/wwwroot/js/site.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/wwwroot/js/site.js#L2

'downloadFile' is defined but never used.
const binaryString = window.atob(base64Content);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);

Check warning on line 6 in EstateManagementUI.BlazorServer/wwwroot/js/site.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

EstateManagementUI.BlazorServer/wwwroot/js/site.js#L6

Generic Object Injection Sink
}
const blob = new Blob([bytes], { type: 'application/octet-stream' });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
}