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 @@ -722,6 +722,25 @@ public async Task MerchantDomainService_MakeMerchantWithdrawal_NotEnoughFundsToW
result.IsFailed.ShouldBeTrue();
}

[Fact]
public async Task MerchantDomainService_MakeMerchantWithdrawal_InvalidBalanceProjection_ResultIsFailed() {
this.AggregateService.Setup(e => e.Get<EstateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(TestData.Aggregates.CreatedEstateAggregate());

this.AggregateService.Setup(m => m.Get<MerchantAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Success(TestData.Aggregates.CreatedMerchantAggregate()));

this.AggregateService
.Setup(m => m.GetLatest<MerchantDepositListAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Success(TestData.Aggregates.CreatedMerchantDepositListAggregate()));

this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Success<String>("null"));

var result = await this.DomainService.MakeMerchantWithdrawal(TestData.Commands.MakeMerchantWithdrawalCommand, CancellationToken.None);
result.IsFailed.ShouldBeTrue();
}

[Fact]
public async Task MerchantDomainService_AddContractToMerchant_ContractAdded() {
this.AggregateService.Setup(e => e.Get<EstateAggregate>(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
Expand Down Expand Up @@ -1909,4 +1928,4 @@ public async Task MerchantDomainService_RemoveContractFromMerchant_ExceptionThro
var result = await this.DomainService.RemoveContractFromMerchant(TestData.Commands.RemoveMerchantContractCommand, CancellationToken.None);
result.IsFailed.ShouldBeTrue();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -363,48 +363,17 @@ public async Task<Result> MakeMerchantWithdrawal(MerchantCommands.MakeMerchantWi

try
{
Result<EstateAggregate> estateResult = await DomainServiceHelper.GetAggregateOrFailure(ct => this.AggregateService.Get<EstateAggregate>(command.EstateId, ct), command.EstateId, cancellationToken);
if (estateResult.IsFailed)
return ResultHelpers.CreateFailure(estateResult);

Result<MerchantAggregate> merchantResult = await DomainServiceHelper.GetAggregateOrFailure(ct => this.AggregateService.Get<MerchantAggregate>(command.MerchantId, ct), command.MerchantId, cancellationToken);
if (merchantResult.IsFailed)
return ResultHelpers.CreateFailure(merchantResult);

EstateAggregate estateAggregate = estateResult.Data;
MerchantAggregate merchantAggregate = merchantResult.Data;

Result validateResult =
this.ValidateEstateAndMerchant(estateAggregate, merchantAggregate);
if (validateResult.IsFailed)
return ResultHelpers.CreateFailure(validateResult);

Result<MerchantDepositListAggregate> getDepositListResult = await DomainServiceHelper.GetAggregateOrFailure(ct => this.AggregateService.GetLatest<MerchantDepositListAggregate>(command.MerchantId, ct), command.MerchantId, cancellationToken);
Result<MerchantDepositListAggregate> getDepositListResult = await this.GetMerchantDepositListForWithdrawal(command, cancellationToken);
if (getDepositListResult.IsFailed)
return ResultHelpers.CreateFailure(getDepositListResult);

MerchantDepositListAggregate merchantDepositListAggregate = getDepositListResult.Data;
if (merchantDepositListAggregate.IsCreated == false)
{
return Result.Invalid($"Merchant [{command.MerchantId}] has not made any deposits yet");
}

// Now we need to check the merchants balance to ensure they have funds to withdraw
Result<String> getBalanceResult = await this.EventStoreContext.GetPartitionStateFromProjection("MerchantBalanceProjection", $"MerchantBalance-{command.MerchantId:N}", cancellationToken);
if (getBalanceResult.IsFailed)
{
return Result.Invalid($"Failed to get Merchant Balance.");
}

MerchantBalanceProjectionState1 projectionState = JsonConvert.DeserializeObject<MerchantBalanceProjectionState1>(getBalanceResult.Data);

if (command.RequestDto.Amount > projectionState.merchant.balance)
{
return Result.Invalid($"Not enough credit available for withdrawal of [{command.RequestDto.Amount}]. Balance is {projectionState.merchant.balance}");
}
Result validateBalanceResult = await this.ValidateWithdrawalBalance(command, cancellationToken);
if (validateBalanceResult.IsFailed)
return validateBalanceResult;

// If we are here we have enough credit to withdraw
PositiveMoney amount = PositiveMoney.Create(Money.Create(command.RequestDto.Amount));
MerchantDepositListAggregate merchantDepositListAggregate = getDepositListResult.Data;

Result stateResult = merchantDepositListAggregate.MakeWithdrawal(command.RequestDto.WithdrawalDateTime, amount);
if (stateResult.IsFailed)
Expand Down Expand Up @@ -734,6 +703,57 @@ private Result ValidateEstateAndMerchant(EstateAggregate estateAggregate,
return Result.Success();
}

private async Task<Result<MerchantDepositListAggregate>> GetMerchantDepositListForWithdrawal(MerchantCommands.MakeMerchantWithdrawalCommand command,
CancellationToken cancellationToken)
{
Result<EstateAggregate> estateResult = await DomainServiceHelper.GetAggregateOrFailure(ct => this.AggregateService.Get<EstateAggregate>(command.EstateId, ct), command.EstateId, cancellationToken);
if (estateResult.IsFailed)
return ResultHelpers.CreateFailure(estateResult);

Result<MerchantAggregate> merchantResult = await DomainServiceHelper.GetAggregateOrFailure(ct => this.AggregateService.Get<MerchantAggregate>(command.MerchantId, ct), command.MerchantId, cancellationToken);
if (merchantResult.IsFailed)
return ResultHelpers.CreateFailure(merchantResult);

Result validateResult = this.ValidateEstateAndMerchant(estateResult.Data, merchantResult.Data);
if (validateResult.IsFailed)
return ResultHelpers.CreateFailure(validateResult);

Result<MerchantDepositListAggregate> getDepositListResult = await DomainServiceHelper.GetAggregateOrFailure(ct => this.AggregateService.GetLatest<MerchantDepositListAggregate>(command.MerchantId, ct), command.MerchantId, cancellationToken);
if (getDepositListResult.IsFailed)
return ResultHelpers.CreateFailure(getDepositListResult);

MerchantDepositListAggregate merchantDepositListAggregate = getDepositListResult.Data;
if (merchantDepositListAggregate.IsCreated == false)
{
return Result.Invalid($"Merchant [{command.MerchantId}] has not made any deposits yet");
}

return Result.Success(merchantDepositListAggregate);
}

private async Task<Result> ValidateWithdrawalBalance(MerchantCommands.MakeMerchantWithdrawalCommand command,
CancellationToken cancellationToken)
{
Result<String> getBalanceResult = await this.EventStoreContext.GetPartitionStateFromProjection("MerchantBalanceProjection", $"MerchantBalance-{command.MerchantId:N}", cancellationToken);
if (getBalanceResult.IsFailed)
{
return Result.Invalid($"Failed to get Merchant Balance.");
}

MerchantBalanceProjectionState1 projectionState = JsonConvert.DeserializeObject<MerchantBalanceProjectionState1>(getBalanceResult.Data);
if (projectionState?.merchant == null)
{
return Result.Invalid("Merchant Balance data is missing or invalid.");
}

if (command.RequestDto.Amount > projectionState.merchant.balance)
{
return Result.Invalid($"Not enough credit available for withdrawal of [{command.RequestDto.Amount}]. Balance is {projectionState.merchant.balance}");
}

return Result.Success();
}

public async Task<Result> SwapMerchantDevice(MerchantCommands.SwapMerchantDeviceCommand command,
CancellationToken cancellationToken)
{
Expand Down
Loading