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 @@ -109,38 +109,7 @@ await merchantStatementDomainService.AddTransactionToStatement(TestData.EstateId
var statementLines = merchantStatement.GetStatementLines();
statementLines.ShouldBeEmpty();
}

[Fact]
public async Task MerchantStatementDomainService_AddTransactionToStatement_MerchantNotCreated_TransactionNotAddedToStatement()
{
Mock<IAggregateRepository<MerchantAggregate, DomainEventRecord.DomainEvent>> merchantAggregateRepository =
new Mock<IAggregateRepository<MerchantAggregate, DomainEventRecord.DomainEvent>>();
merchantAggregateRepository.Setup(m => m.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(new MerchantAggregate());

MerchantStatementAggregate merchantStatementAggregate = TestData.CreatedMerchantStatementAggregate();

Mock<IAggregateRepository<MerchantStatementAggregate, DomainEventRecord.DomainEvent>> merchantStatementAggregateRepository =
new Mock<IAggregateRepository<MerchantStatementAggregate, DomainEventRecord.DomainEvent>>();
merchantStatementAggregateRepository.Setup(m => m.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(merchantStatementAggregate);
MerchantStatementDomainService merchantStatementDomainService =
new MerchantStatementDomainService(merchantAggregateRepository.Object, merchantStatementAggregateRepository.Object);

Should.NotThrow(async () =>
{
await merchantStatementDomainService.AddTransactionToStatement(TestData.EstateId,
TestData.MerchantId,
TestData.TransactionDateTime1,
TestData.TransactionAmount1,
TestData.IsAuthorisedTrue,
TestData.TransactionId1,
CancellationToken.None);
});

var merchantStatement = merchantStatementAggregate.GetStatement(true);
var statementLines = merchantStatement.GetStatementLines();
statementLines.ShouldBeEmpty();
}


[Fact]
public async Task MerchantStatementDomainService_AddTransactionToStatement_StatementNotAlreadyCreated_TransactionAdded()
{
Expand Down Expand Up @@ -203,37 +172,6 @@ await merchantStatementDomainService.AddSettledFeeToStatement(TestData.EstateId,
statementLines.Count.ShouldBe(2);
}

[Fact]
public async Task MerchantStatementDomainService_AddSettledFeeToStatement_MerchantNotCreated_SettledFeeNotAddedToStatement()
{
Mock<IAggregateRepository<MerchantAggregate, DomainEventRecord.DomainEvent>> merchantAggregateRepository =
new Mock<IAggregateRepository<MerchantAggregate, DomainEventRecord.DomainEvent>>();
merchantAggregateRepository.Setup(m => m.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(new MerchantAggregate());

MerchantStatementAggregate merchantStatementAggregate = TestData.MerchantStatementAggregateWithTransactionLineAdded();

Mock<IAggregateRepository<MerchantStatementAggregate, DomainEventRecord.DomainEvent>> merchantStatementAggregateRepository =
new Mock<IAggregateRepository<MerchantStatementAggregate, DomainEventRecord.DomainEvent>>();
merchantStatementAggregateRepository.Setup(m => m.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(merchantStatementAggregate);
MerchantStatementDomainService merchantStatementDomainService =
new MerchantStatementDomainService(merchantAggregateRepository.Object, merchantStatementAggregateRepository.Object);

Should.NotThrow(async () =>
{
await merchantStatementDomainService.AddSettledFeeToStatement(TestData.EstateId,
TestData.MerchantId,
TestData.SettledFeeDateTime1,
TestData.SettledFeeAmount1,
TestData.TransactionId1,
TestData.SettledFeeId1,
CancellationToken.None);
});

var merchantStatement = merchantStatementAggregate.GetStatement(true);
var statementLines = merchantStatement.GetStatementLines();
statementLines.ShouldNotBeEmpty();
statementLines.Count.ShouldBe(1);
}

[Fact]
public async Task MerchantStatementDomainService_GenerateStatement_StatementGenerated()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace EstateManagement.BusinessLogic.EventHandling
{
using System;
using System.Threading;
using System.Threading.Tasks;
using MediatR;
Expand Down Expand Up @@ -57,6 +58,7 @@ public async Task Handle(IDomainEvent domainEvent,
private async Task HandleSpecificDomainEvent(MerchantFeeSettledEvent domainEvent,
CancellationToken cancellationToken)
{
//throw new Exception();
AddSettledFeeToMerchantStatementRequest addSettledFeeToMerchantStatementRequest = AddSettledFeeToMerchantStatementRequest.Create(domainEvent.EstateId,
domainEvent.MerchantId,
domainEvent.EventTimestamp.DateTime,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
namespace EstateManagement.BusinessLogic.EventHandling
{
using System;
using System.Threading;
using System.Threading.Tasks;
using Common;
using MediatR;
using Requests;
using Services;
using Shared.DomainDrivenDesign.EventSourcing;
using Shared.EventStore.EventHandling;
using Shared.Logger;
using TransactionProcessor.Transaction.DomainEvents;

/// <summary>
Expand Down Expand Up @@ -66,7 +70,7 @@ private async Task HandleSpecificDomainEvent(TransactionHasBeenCompletedEvent do

await this.Mediator.Send(addTransactionToMerchantStatementRequest, cancellationToken);
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,9 @@ public async Task CreateMerchant(Guid estateId,
// Create the merchant
if (merchantAggregate.IsCreated)
{
merchantAggregate.Create(estateId, name, DateTime.Now);
merchantAggregate.Create(estateId, name, merchantAggregate.DateCreated);
merchantAggregate.GenerateReference();
merchantAggregate.SetStatementDate(new DateTime(2021,9,1));
}
else
{
Expand All @@ -136,6 +137,9 @@ public async Task CreateMerchant(Guid estateId,

// Set the settlement schedule
merchantAggregate.SetSettlementSchedule(settlementSchedule);

// Set the next statement date
merchantAggregate.SetStatementDate(DateTime.Now);
}

await this.MerchantAggregateRepository.SaveChanges(merchantAggregate, cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using MerchantAggregate;
using MerchantStatementAggregate;
using Models.MerchantStatement;
using NLog;
using Shared.DomainDrivenDesign.EventSourcing;
using Shared.EventStore.Aggregate;

Expand Down Expand Up @@ -66,32 +67,41 @@ public async Task AddSettledFeeToStatement(Guid estateId,
Guid settledFeeId,
CancellationToken cancellationToken)
{
// Merchant is rehydrated
MerchantAggregate merchant = await this.MerchantAggregateRepository.GetLatestVersion(merchantId, cancellationToken);
if (merchant.IsCreated == false)
return;

// Work out the next statement date (how is this done), do we feed statement generated events back into the merchant to update the statement date? Statements will be monthly!!
// TODO: Statement date
DateTime nextStatementDate = Guid.Parse("b5963507-c561-08d9-0000-000000000000").ToDateTime();
// Work out the next statement date
DateTime nextStatementDate = CalculateStatementDate(settledDateTime);

Guid statementId = GuidCalculator.Combine(merchantId, nextStatementDate.ToGuid());
Guid settlementFeeId = GuidCalculator.Combine(transactionId, settledFeeId);
MerchantStatementAggregate merchantStatementAggregate =
await this.MerchantStatementAggregateRepository.GetLatestVersion(nextStatementDate.ToGuid(), cancellationToken);
await this.MerchantStatementAggregateRepository.GetLatestVersion(statementId, cancellationToken);

MerchantStatement merchantStatement = merchantStatementAggregate.GetStatement();
if (merchantStatement.IsCreated == false)
{
merchantStatementAggregate.CreateStatement(estateId, merchantId, nextStatementDate);
}

// Add settled fee to statement
SettledFee settledFee = new SettledFee
{
DateTime = settledDateTime,
Amount = settledAmount,
TransactionId = transactionId,
SettledFeeId = settledFeeId
};
SettledFeeId = settlementFeeId
};

merchantStatementAggregate.AddSettledFeeToStatement(settledFee);

await this.MerchantStatementAggregateRepository.SaveChanges(merchantStatementAggregate, cancellationToken);
}

internal static DateTime CalculateStatementDate(DateTime eventDateTime)
{
var calculatedDateTime = eventDateTime.Date.AddMonths(1);

return new DateTime(calculatedDateTime.Year, calculatedDateTime.Month, 1);
}

/// <summary>
/// Generates the statement.
/// </summary>
Expand All @@ -114,7 +124,7 @@ public async Task<Guid> GenerateStatement(Guid estateId,

return merchantStatementAggregate.AggregateId;
}

/// <summary>
/// Adds the transaction to statement.
/// </summary>
Expand All @@ -133,24 +143,19 @@ public async Task AddTransactionToStatement(Guid estateId,
Guid transactionId,
CancellationToken cancellationToken)
{
// TODO: Move to domain service
// Transaction Completed arrives (if this is a logon transaction or failed then return)
// Transaction Completed arrives(if this is a logon transaction or failed then return)
if (isAuthorised == false)
return;
if (transactionAmount.HasValue == false)
return;

// Merchant is rehydrated
MerchantAggregate merchant = await this.MerchantAggregateRepository.GetLatestVersion(merchantId, cancellationToken);
if (merchant.IsCreated == false)
return;
// Work out the next statement date
DateTime nextStatementDate = CalculateStatementDate(transactionDateTime);

// Work out the next statement date (how is this done), do we feed statement generated events back into the merchant to update the statement date? Statements will be monthly!!
// TODO: Statement date
DateTime nextStatementDate = DateTime.Now.AddDays(7);
Guid statementId = GuidCalculator.Combine(merchantId, nextStatementDate.ToGuid());

MerchantStatementAggregate merchantStatementAggregate =
await this.MerchantStatementAggregateRepository.GetLatestVersion(nextStatementDate.ToGuid(), cancellationToken);
await this.MerchantStatementAggregateRepository.GetLatestVersion(statementId, cancellationToken);
MerchantStatement merchantStatement = merchantStatementAggregate.GetStatement();

if (merchantStatement.IsCreated == false)
Expand All @@ -160,11 +165,11 @@ public async Task AddTransactionToStatement(Guid estateId,

// Add transaction to statement
Transaction transaction = new Transaction
{
DateTime = transactionDateTime,
Amount = transactionAmount.Value,
TransactionId = transactionId
};
{
DateTime = transactionDateTime,
Amount = transactionAmount.Value,
TransactionId = transactionId
};

merchantStatementAggregate.AddTransactionToStatement(transaction);

Expand All @@ -173,4 +178,95 @@ public async Task AddTransactionToStatement(Guid estateId,

#endregion
}

public static class GuidCalculator
{
#region Methods

/// <summary>
/// Combines the specified GUIDs into a new GUID.
/// </summary>
/// <param name="firstGuid">The first unique identifier.</param>
/// <param name="secondGuid">The second unique identifier.</param>
/// <param name="offset">The offset.</param>
/// <returns>Guid.</returns>
public static Guid Combine(Guid firstGuid,
Guid secondGuid,
Byte offset)
{
Byte[] firstAsBytes = firstGuid.ToByteArray();
Byte[] secondAsBytes = secondGuid.ToByteArray();

Byte[] newBytes = new Byte[16];

for (Int32 i = 0; i < 16; i++)
{
// Add and truncate any overflow
newBytes[i] = (Byte)(firstAsBytes[i] + secondAsBytes[i] + offset);
}

return new Guid(newBytes);
}

/// <summary>
/// Combines the specified GUIDs into a new GUID.
/// </summary>
/// <param name="firstGuid">The first unique identifier.</param>
/// <param name="secondGuid">The second unique identifier.</param>
/// <returns>Guid.</returns>
public static Guid Combine(Guid firstGuid,
Guid secondGuid)
{
return GuidCalculator.Combine(firstGuid,
secondGuid,
0);
}

/// <summary>
/// Combines the specified first unique identifier.
/// </summary>
/// <param name="firstGuid">The first unique identifier.</param>
/// <param name="secondGuid">The second unique identifier.</param>
/// <param name="thirdGuid">The third unique identifier.</param>
/// <param name="offset">The offset.</param>
/// <returns>Guid.</returns>
public static Guid Combine(Guid firstGuid,
Guid secondGuid,
Guid thirdGuid,
Byte offset)
{
Byte[] firstAsBytes = firstGuid.ToByteArray();
Byte[] secondAsBytes = secondGuid.ToByteArray();
Byte[] thirdAsBytes = thirdGuid.ToByteArray();

Byte[] newBytes = new Byte[16];

for (Int32 i = 0; i < 16; i++)
{
// Add and truncate any overflow
newBytes[i] = (Byte)(firstAsBytes[i] + secondAsBytes[i] + thirdAsBytes[i] + offset);
}

return new Guid(newBytes);
}

/// <summary>
/// Combines the specified first unique identifier.
/// </summary>
/// <param name="firstGuid">The first unique identifier.</param>
/// <param name="secondGuid">The second unique identifier.</param>
/// <param name="thirdGuid">The third unique identifier.</param>
/// <returns>Guid.</returns>
public static Guid Combine(Guid firstGuid,
Guid secondGuid,
Guid thirdGuid)
{
return GuidCalculator.Combine(firstGuid,
secondGuid,
thirdGuid,
0);
}

#endregion
}
}
Loading