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 @@ -75,7 +75,6 @@ public static Result MakeDeposit(this MerchantDepositListAggregate aggregate,
if (result.IsFailed)
return result;

// TODO: Change amount to a value object (PositiveAmount VO)
result = aggregate.EnsureDepositSourceHasBeenSet(source);
if (result.IsFailed)
return result;
Expand Down
2 changes: 0 additions & 2 deletions TransactionProcessor.Aggregates/MerchantStatementAggregate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,6 @@ public static Result AddDailySummaryRecord(this MerchantStatementAggregate aggre
return Result.Success();
}

// TODO: should this check the date has been added to the statement, before allowing the summary?

MerchantStatementDomainEvents.StatementSummaryForDateEvent statementSummaryForDateEvent = new(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, activityDate,aggregate.MerchantStatementSummaries.Count +1
,numberOfTransactions, valueOfTransactions, numberOfSettledFees, valueOfSettledFees, numberOfDepoits, valueOfDepoits, numberOfWithdrawals, valueOfWithdrawals);
aggregate.ApplyAndAppend(statementSummaryForDateEvent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,6 @@ public async Task<Result> Handle(IDomainEvent domainEvent,
private async Task<String> GetVoucherOperator(Models.Voucher voucherModel,
CancellationToken cancellationToken)
{
// TODO: Can this be done in a better way than direct db access ?

using ResolvedDbContext<EstateManagementContext>? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, voucherModel.EstateId.ToString());
await using EstateManagementContext context = resolvedContext.Context;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,6 @@ public async Task<Result<List<Merchant>>> GetMerchants(Guid estateId,
Guid productId,
CancellationToken cancellationToken)
{
// TODO: this will need updated to handle merchant specific fees when that is available

Result<ContractAggregate> getContractResult = await this.AggregateService.GetLatest<ContractAggregate>(contractId, cancellationToken);
if (getContractResult.IsFailed)
return ResultHelpers.CreateFailure(getContractResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ public class SettlementDomainService : ISettlementDomainService
{
private readonly IAggregateService AggregateService;

// TODO: Add in a Get Settlement

public async Task<Result<Guid>> ProcessSettlement(SettlementCommands.ProcessSettlementCommand command,
CancellationToken cancellationToken) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,19 +274,7 @@ public async Task<Result<ProcessSaleTransactionResponse>> ProcessSaleTransaction
operatorStartDateTime =DateTime.Now;
Result<OperatorResponse> operatorResult = await this.ProcessMessageWithOperator(merchantResult.Data, command.TransactionId, command.TransactionDateTime, command.OperatorId, command.AdditionalTransactionMetadata, transactionReference, cancellationToken);
operatorEndDateTime = DateTime.Now;
// Act on the operator response
// TODO: see if we still need this case...
//if (operatorResult.IsFailed) {
// // Failed to perform sed/receive with the operator
// TransactionResponseCode transactionResponseCode =
// TransactionResponseCode.OperatorCommsError;
// String responseMessage = "OPERATOR COMMS ERROR";

// transactionAggregate.DeclineTransactionLocally(
// ((Int32)transactionResponseCode).ToString().PadLeft(4, '0'), responseMessage);
//}
//else {


if (operatorResult.IsSuccess) {
TransactionResponseCode transactionResponseCode = TransactionResponseCode.Success;
String responseMessage = "SUCCESS";
Expand Down Expand Up @@ -405,12 +393,12 @@ public async Task<Result> CalculateFeesForTransaction(TransactionCommands.Calcul
if (RequireFeeCalculation(transactionAggregate) == false)
return Result.Success();

List<TransactionFeeToCalculate> feesForCalculation = await this.GetTransactionFeesForCalculation(transactionAggregate, cancellationToken);
Result<List<TransactionFeeToCalculate>> feesForCalculationResult = await this.GetTransactionFeesForCalculation(transactionAggregate, cancellationToken);

if (feesForCalculation == null)
return Result.Failure("Error getting transaction fees");
if (feesForCalculationResult.IsFailed)
return ResultHelpers.CreateFailure(feesForCalculationResult);

List<CalculatedFee> resultFees = this.FeeCalculationManager.CalculateFees(feesForCalculation, transactionAggregate.TransactionAmount.Value, command.CompletedDateTime);
List<CalculatedFee> resultFees = this.FeeCalculationManager.CalculateFees(feesForCalculationResult.Data, transactionAggregate.TransactionAmount.Value, command.CompletedDateTime);

IEnumerable<CalculatedFee> nonMerchantFees = resultFees.Where(f => f.FeeType == TransactionProcessor.Models.Contract.FeeType.ServiceProvider);
foreach (CalculatedFee calculatedFee in nonMerchantFees) {
Expand Down Expand Up @@ -558,15 +546,14 @@ internal static DateTime CalculateSettlementDate(Models.Merchant.SettlementSched
return completeDateTime.Date;
}

private async Task<List<TransactionFeeToCalculate>> GetTransactionFeesForCalculation(TransactionAggregate transactionAggregate,
private async Task<Result<List<TransactionFeeToCalculate>>> GetTransactionFeesForCalculation(TransactionAggregate transactionAggregate,
CancellationToken cancellationToken) {
// TODO: convert to result??
// Get the fees to be calculated
Result<List<ContractProductTransactionFee>> feesForProduct = await this.GetTransactionFeesForProduct(transactionAggregate.ContractId, transactionAggregate.ProductId, cancellationToken);

if (feesForProduct.IsFailed) {
Logger.LogWarning($"Failed to get fees {feesForProduct.Message}");
return null;
return ResultHelpers.CreateFailure(feesForProduct);
}

Logger.LogInformation($"After getting Fees {feesForProduct.Data.Count} returned");
Expand All @@ -579,7 +566,7 @@ private async Task<List<TransactionFeeToCalculate>> GetTransactionFeesForCalcula
feesForCalculation.Add(transactionFeeToCalculate);
}

return feesForCalculation;
return Result.Success(feesForCalculation);
}

private async Task<Result> AddDeviceToMerchant(Guid merchantId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public class MerchantStatementLine
/// </value>
public String Description { get; set; }

// TODO: maybe make this an enum type
/// <summary>
/// Gets or sets the type of the line.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,10 @@ namespace TransactionProcessor.ProjectionEngine.EventHandling
public class EventHandler : IDomainEventHandler
{
private readonly Func<String, IDomainEventHandler> Resolver;

public static Dictionary<String, Type> StateTypes;


public EventHandler(Func<String, IDomainEventHandler> resolver)
{
this.Resolver = resolver;
List<Type> subclassTypes = Assembly.GetAssembly(typeof(Shared.EventStore.ProjectionEngine.State))?.GetTypes().Where(t => t.IsSubclassOf(typeof(Shared.EventStore.ProjectionEngine.State))).ToList();

if (subclassTypes != null)
{
EventHandler.StateTypes = subclassTypes.ToDictionary(x => x.Name, x => x);
}
}

public async Task<Result> Handle(IDomainEvent domainEvent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1161,7 +1161,8 @@ public async Task<Result> DisableContractProductTransactionFee(ContractDomainEve
EstateManagementContext context = await this.GetContext(domainEvent.EstateId);

Result<ContractProductTransactionFee> loadContractProductTransactionFeeResult = await context.LoadContractProductTransactionFee(domainEvent, cancellationToken);
// TODO: Check the result value
if (loadContractProductTransactionFeeResult.IsFailed)
return ResultHelpers.CreateFailure(loadContractProductTransactionFeeResult);

ContractProductTransactionFee transactionFee = loadContractProductTransactionFeeResult.Data;

Expand All @@ -1174,7 +1175,6 @@ public async Task<Result> MarkMerchantFeeAsSettled(SettlementDomainEvents.Mercha
CancellationToken cancellationToken) {
EstateManagementContext context = await this.GetContext(domainEvent.EstateId);

// TODO: LoadMerchantSettlementFee
MerchantSettlementFee merchantFee = await context.MerchantSettlementFees.Where(m =>
m.MerchantId == domainEvent.MerchantId &&
m.TransactionId == domainEvent.TransactionId &&
Expand Down
64 changes: 34 additions & 30 deletions TransactionProcessor/Bootstrapper/RepositoryRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,24 @@
[ExcludeFromCodeCoverage]
public class RepositoryRegistry : ServiceRegistry
{
#region Constructors
private static bool CachedAggregatesAdded;
private static readonly object CachedAggregatesLock = new();

private static Boolean CachedAggregatesAdded;
/// <summary>
/// Initializes a new instance of the <see cref="RepositoryRegistry"/> class.
/// </summary>
public RepositoryRegistry()
{
String eventStoreConnectionString = Startup.Configuration.GetValue<String>("EventStoreSettings:ConnectionString");
string eventStoreConnectionString = Startup.Configuration.GetValue<string>("EventStoreSettings:ConnectionString");

this.AddEventStoreProjectionManagementClient(eventStoreConnectionString);
this.AddEventStorePersistentSubscriptionsClient(eventStoreConnectionString);

this.AddEventStoreClient(eventStoreConnectionString);

this.AddSingleton<Func<String, Int32, ISubscriptionRepository>>(cont => (esConnString, cacheDuration) => {
return SubscriptionRepository.Create(esConnString, cacheDuration);
});
this.AddSingleton<Func<string, int, ISubscriptionRepository>>(cont => (esConnString, cacheDuration) =>
SubscriptionRepository.Create(esConnString, cacheDuration));

this.AddSingleton(typeof(IDbContextResolver<>), typeof(DbContextResolver<>));
if (Startup.WebHostEnvironment.IsEnvironment("IntegrationTest") || Startup.Configuration.GetValue<Boolean>("ServiceOptions:UseInMemoryDatabase") == true)

if (Startup.WebHostEnvironment.IsEnvironment("IntegrationTest") ||
Startup.Configuration.GetValue<bool>("ServiceOptions:UseInMemoryDatabase"))
{
this.AddDbContext<EstateManagementContext>(builder => builder.UseInMemoryDatabase("TransactionProcessorReadModel"));
}
Expand All @@ -67,28 +64,37 @@
}

this.AddTransient<IEventStoreContext, EventStoreContext>();
this.AddSingleton<Func<IAggregateService>>(c => () => {

IAggregateService aggregateService = Startup.ServiceProvider.GetService<IAggregateService>();
if (RepositoryRegistry.CachedAggregatesAdded == false)

// ✅ Defer to the container — safe and compliant
this.AddSingleton<Func<IAggregateService>>(c => () =>
{
var aggregateService = c.GetService<IAggregateService>();

// Thread-safe single initialization
if (!CachedAggregatesAdded)
{
aggregateService.AddCachedAggregate(typeof(EstateAggregate), null);
aggregateService.AddCachedAggregate(typeof(ContractAggregate), null);
aggregateService.AddCachedAggregate(typeof(OperatorAggregate), null);
aggregateService.AddCachedAggregate(typeof(MerchantAggregate), null);
RepositoryRegistry.CachedAggregatesAdded=true;
lock (CachedAggregatesLock)
{
if (!CachedAggregatesAdded)
{
aggregateService.AddCachedAggregate(typeof(EstateAggregate), null);
aggregateService.AddCachedAggregate(typeof(ContractAggregate), null);
aggregateService.AddCachedAggregate(typeof(OperatorAggregate), null);
aggregateService.AddCachedAggregate(typeof(MerchantAggregate), null);

CachedAggregatesAdded = true;

Check warning on line 85 in TransactionProcessor/Bootstrapper/RepositoryRegistry.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

TransactionProcessor/Bootstrapper/RepositoryRegistry.cs#L85

Remove this assignment of 'CachedAggregatesAdded' or initialize it statically.
}
}
}

return aggregateService;
});

this.AddSingleton<IAggregateService, AggregateService>();
this.AddSingleton<IAggregateRepositoryResolver, AggregateRepositoryResolver>();
this.AddSingleton<IAggregateRepository<TransactionAggregate, DomainEvent>,
AggregateRepository<TransactionAggregate, DomainEvent>>();
this.AddSingleton<IAggregateRepository<ReconciliationAggregate, DomainEvent>,
AggregateRepository<ReconciliationAggregate, DomainEvent>>();
this.AddSingleton<IAggregateRepository<SettlementAggregate, DomainEvent>,
AggregateRepository<SettlementAggregate, DomainEvent>>();
this.AddSingleton<IAggregateRepository<TransactionAggregate, DomainEvent>, AggregateRepository<TransactionAggregate, DomainEvent>>();
this.AddSingleton<IAggregateRepository<ReconciliationAggregate, DomainEvent>, AggregateRepository<ReconciliationAggregate, DomainEvent>>();
this.AddSingleton<IAggregateRepository<SettlementAggregate, DomainEvent>, AggregateRepository<SettlementAggregate, DomainEvent>>();
this.AddSingleton<IAggregateRepository<VoucherAggregate, DomainEvent>, AggregateRepository<VoucherAggregate, DomainEvent>>();
this.AddSingleton<IAggregateRepository<FloatAggregate, DomainEvent>, AggregateRepository<FloatAggregate, DomainEvent>>();
this.AddSingleton<IAggregateRepository<FloatActivityAggregate, DomainEvent>, AggregateRepository<FloatActivityAggregate, DomainEvent>>();
Expand All @@ -99,17 +105,15 @@
this.AddSingleton<IAggregateRepository<MerchantDepositListAggregate, DomainEvent>, AggregateRepository<MerchantDepositListAggregate, DomainEvent>>();
this.AddSingleton<IAggregateRepository<MerchantStatementAggregate, DomainEvent>, AggregateRepository<MerchantStatementAggregate, DomainEvent>>();
this.AddSingleton<IAggregateRepository<MerchantStatementForDateAggregate, DomainEvent>, AggregateRepository<MerchantStatementForDateAggregate, DomainEvent>>();

this.AddSingleton<IProjectionStateRepository<MerchantBalanceState>, MerchantBalanceStateRepository>();
this.AddSingleton<IProjectionStateRepository<VoucherState>, VoucherStateRepository>();
this.AddSingleton<ITransactionProcessorReadRepository, TransactionProcessorReadRepository>();
this.AddSingleton<ITransactionProcessorReadModelRepository, TransactionProcessorReadModelRepository>();
this.AddSingleton<IProjection<MerchantBalanceState>, MerchantBalanceProjection>();
}

#endregion
}


[ExcludeFromCodeCoverage]
public class ConfigurationReaderConnectionStringRepository : IConnectionStringConfigurationRepository
{
Expand Down
Loading
Loading