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 @@ -82,27 +82,54 @@ public void MerchantStatementForDateAggregate_AddSettledFeeToStatement_Duplicate
statementLines.Count.ShouldBe(1);
}

/*
[Fact]
public void MerchantStatementAggregate_AddDailySummaryRecord_RecordIsAdded() {
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
Should.NotThrow(() => { merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m); });
}

[Fact]
public void MerchantStatementAggregate_AddDailySummaryRecord_DuplicateAdd_ExceptionIsThrown()
{
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m);
Should.Throw<InvalidOperationException>(() => { merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m); });
}


[Fact]
public void MerchantStatementAggregate_GenerateStatement_StatementIsGenerated()
{
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
merchantStatementAggregate.AddTransactionToStatement(TestData.MerchantStatementId,
TestData.EventId1,
TestData.StatementCreateDate,
TestData.EstateId,
TestData.MerchantId, TestData.Transaction1);
merchantStatementAggregate.AddSettledFeeToStatement(TestData.MerchantStatementId,
TestData.EventId1,
TestData.StatementCreateDate,
TestData.EstateId,
TestData.MerchantId, TestData.SettledFee1);
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m);
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);

var merchantStatement = merchantStatementAggregate.GetStatement();
MerchantStatement merchantStatement = merchantStatementAggregate.GetStatement();
merchantStatement.IsGenerated.ShouldBeTrue();
}

[Fact]
public void MerchantStatementAggregate_GenerateStatement_StatementIsAlreadGenerated_ExceptionThrown()
{
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);
merchantStatementAggregate.AddDailySummaryRecord(TestData.TransactionDateTime.Date, 1, 100.00m, 1, 0.10m);
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
Should.Throw<InvalidOperationException>(() => {
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
});
}

[Fact]
public void MerchantStatementAggregate_GenerateStatement_NoSummaries_ExceptionThrown()
{
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);

Should.Throw<InvalidOperationException>(() => {
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
});
}

/*
[Fact]
public void MerchantStatementAggregate_GenerateStatement_StatementNotCreated_ErrorThrown()
{
Expand Down Expand Up @@ -140,13 +167,13 @@ public void MerchantStatementAggregate_GenerateStatement_StatementAlreadyGenerat
public void MerchantStatementAggregate_GenerateStatement_StatementHasNoTransactionsOrSettledFees_ErrorThrown()
{
MerchantStatementAggregate merchantStatementAggregate = MerchantStatementAggregate.Create(TestData.MerchantStatementId);

Should.Throw<InvalidOperationException>(() =>
{
merchantStatementAggregate.GenerateStatement(TestData.StatementGeneratedDate);
});
}

[Fact]
public void MerchantStatementAggregate_EmailStatement_StatementHasBeenEmailed()
{
Expand Down
71 changes: 47 additions & 24 deletions TransactionProcessor.Aggregates/MerchantStatementAggregate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public record MerchantStatementAggregate : Aggregate
internal Guid MerchantId;

internal List<(Guid merchantStatementForDateId, DateTime activityDate)> ActivityDates;

internal List<MerchantStatementSummary> MerchantStatementSummaries;
#endregion

#region Constructors
Expand All @@ -41,6 +43,7 @@ public MerchantStatementAggregate()
{
// Nothing here
this.ActivityDates = new();
this.MerchantStatementSummaries = new();
}

private MerchantStatementAggregate(Guid aggregateId)
Expand All @@ -49,6 +52,7 @@ private MerchantStatementAggregate(Guid aggregateId)

this.AggregateId = aggregateId;
this.ActivityDates = new();
this.MerchantStatementSummaries = new();
}

#endregion
Expand Down Expand Up @@ -81,11 +85,11 @@ public static void PlayEvent(this MerchantStatementAggregate aggregate, Merchant
aggregate.StatementDate = domainEvent.StatementDate;
}

//public static void PlayEvent(this MerchantStatementAggregate aggregate, MerchantStatementDomainEvents.StatementGeneratedEvent domainEvent)
//{
// aggregate.IsGenerated = true;
// aggregate.GeneratedDateTime = domainEvent.DateGenerated;
//}
public static void PlayEvent(this MerchantStatementAggregate aggregate, MerchantStatementDomainEvents.StatementGeneratedEvent domainEvent)
{
aggregate.IsGenerated = true;
aggregate.GeneratedDateTime = domainEvent.DateGenerated;
}

//public static void PlayEvent(this MerchantStatementAggregate aggregate, MerchantStatementDomainEvents.StatementEmailedEvent domainEvent)
//{
Expand All @@ -98,6 +102,13 @@ public static void PlayEvent(this MerchantStatementAggregate aggregate,
MerchantStatementDomainEvents.ActivityDateAddedToStatementEvent domainEvent) {
aggregate.ActivityDates.Add((domainEvent.MerchantStatementForDateId, domainEvent.ActivityDate));
}

public static void PlayEvent(this MerchantStatementAggregate aggregate,
MerchantStatementDomainEvents.StatementSummaryForDateEvent domainEvent)
{
aggregate.MerchantStatementSummaries.Add(new MerchantStatementSummary(domainEvent.ActivityDate,domainEvent.NumberOfTransactions,domainEvent.ValueOfTransactions,
domainEvent.NumberOfSettledFees,domainEvent.ValueOfTransactions));
}

public static void RecordActivityDateOnStatement(this MerchantStatementAggregate aggregate,
Guid statementId,
Expand Down Expand Up @@ -137,6 +148,7 @@ public static MerchantStatement GetStatement(this MerchantStatementAggregate agg
IsCreated = aggregate.IsCreated,
StatementDate = aggregate.StatementDate,
MerchantStatementId = aggregate.AggregateId,
IsGenerated = aggregate.IsGenerated,
};

foreach ((Guid merchantStatementForDateId, DateTime activityDate) aggregateActivityDate in aggregate.ActivityDates) {
Expand All @@ -158,21 +170,21 @@ public static MerchantStatement GetStatement(this MerchantStatementAggregate agg
// aggregate.ApplyAndAppend(statementEmailedEvent);
//}

//public static void GenerateStatement(this MerchantStatementAggregate aggregate,
// DateTime generatedDateTime)
//{
// aggregate.EnsureStatementHasNotAlreadyBeenGenerated();
public static void GenerateStatement(this MerchantStatementAggregate aggregate,
DateTime generatedDateTime)
{
aggregate.EnsureStatementHasNotAlreadyBeenGenerated();

// // TODO: Validate days have been added
// //if (aggregate.Transactions.Any() == false && aggregate.SettledFees.Any() == false)
// //{
// // throw new InvalidOperationException("Statement has no transactions or settled fees");
// //}
// Validate days have been added
if (aggregate.MerchantStatementSummaries.Any() == false)
{
throw new InvalidOperationException("Statement has no transactions or settled fees");
}

// MerchantStatementDomainEvents.StatementGeneratedEvent statementGeneratedEvent = new(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, generatedDateTime);
MerchantStatementDomainEvents.StatementGeneratedEvent statementGeneratedEvent = new(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, generatedDateTime);

// aggregate.ApplyAndAppend(statementGeneratedEvent);
//}
aggregate.ApplyAndAppend(statementGeneratedEvent);
}

//private static void EnsureStatementHasBeenCreated(this MerchantStatementAggregate aggregate)
//{
Expand All @@ -190,12 +202,23 @@ public static MerchantStatement GetStatement(this MerchantStatementAggregate agg
// }
//}

//private static void EnsureStatementHasNotAlreadyBeenGenerated(this MerchantStatementAggregate aggregate)
//{
// if (aggregate.IsGenerated)
// {
// throw new InvalidOperationException("Statement header has already been generated");
// }
//}
private static void EnsureStatementHasNotAlreadyBeenGenerated(this MerchantStatementAggregate aggregate)
{
if (aggregate.IsGenerated)
{
throw new InvalidOperationException("Statement header has already been generated");
}
}

public static void AddDailySummaryRecord(this MerchantStatementAggregate aggregate, DateTime activityDate, Int32 numberOfTransactions, Decimal valueOfTransactions, Int32 numberOfSettledFees, Decimal valueOfSettledFees) {
if (aggregate.MerchantStatementSummaries.Any(s => s.ActivityDate == activityDate)) {
throw new InvalidOperationException($"Summary Data for Activity Date {activityDate:yyyy-MM-dd} already exists");
}
MerchantStatementDomainEvents.StatementSummaryForDateEvent statementSummaryForDateEvent = new(aggregate.AggregateId, aggregate.EstateId, aggregate.MerchantId, activityDate,aggregate.MerchantStatementSummaries.Count +1
,numberOfTransactions, valueOfTransactions, numberOfSettledFees, valueOfSettledFees);
aggregate.ApplyAndAppend(statementSummaryForDateEvent);
}
}

public record MerchantStatementSummary(DateTime ActivityDate, Int32 NumberOfTransactions, Decimal ValueOfTransactions, Int32 NumberOfSettledFees, Decimal ValueOfSettledFees);
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public MediatorTests()
this.Requests.Add(TestData.Queries.GetTransactionFeesForProductQuery);

// Merchant Statement Commands
//this.Requests.Add(TestData.Commands.GenerateMerchantStatementCommand);
this.Requests.Add(TestData.Commands.GenerateMerchantStatementCommand);
this.Requests.Add(TestData.Commands.AddTransactionToMerchantStatementCommand);
//this.Requests.Add(TestData.Commands.EmailMerchantStatementCommand);
this.Requests.Add(TestData.Commands.AddSettledFeeToMerchantStatementCommand);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<DebugType>None</DebugType>
<DebugType>Full</DebugType>
<IsPackable>false</IsPackable>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace TransactionProcessor.BusinessLogic.RequestHandlers
{
public class MerchantStatementRequestHandler : IRequestHandler<MerchantStatementCommands.AddTransactionToMerchantStatementCommand, Result>,
IRequestHandler<MerchantStatementCommands.AddSettledFeeToMerchantStatementCommand,Result>,
//IRequestHandler<MerchantCommands.GenerateMerchantStatementCommand, Result>,
IRequestHandler<MerchantCommands.GenerateMerchantStatementCommand, Result>,
//IRequestHandler<MerchantStatementCommands.EmailMerchantStatementCommand, Result>,
IRequestHandler<MerchantStatementCommands.RecordActivityDateOnMerchantStatementCommand, Result> {
#region Fields
Expand Down Expand Up @@ -64,10 +64,10 @@ public async Task<Result> Handle(MerchantStatementCommands.AddSettledFeeToMercha

#endregion

//public async Task<Result> Handle(MerchantCommands.GenerateMerchantStatementCommand command, CancellationToken cancellationToken)
//{
// return await this.MerchantStatementDomainService.GenerateStatement(command, cancellationToken);
//}
public async Task<Result> Handle(MerchantCommands.GenerateMerchantStatementCommand command, CancellationToken cancellationToken)
{
return await this.MerchantStatementDomainService.GenerateStatement(command, cancellationToken);
}

//public async Task<Result> Handle(MerchantStatementCommands.EmailMerchantStatementCommand command,
// CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
using Shared.Results;
using SimpleResults;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO.Abstractions;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Google.Protobuf.Reflection;
Expand Down Expand Up @@ -164,29 +166,52 @@
return new DateTime(calculatedDateTime.Year, calculatedDateTime.Month, 1);
}

/// <summary>
/// Generates the statement.
/// </summary>
/// <param name="estateId">The estate identifier.</param>
/// <param name="merchantId">The merchant identifier.</param>
/// <param name="statementDate">The statement date.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
public async Task<Result> GenerateStatement(MerchantCommands.GenerateMerchantStatementCommand command, CancellationToken cancellationToken)
{
//Guid statementId = GuidCalculator.Combine(command.MerchantId, command.RequestDto.MerchantStatementDate.ToGuid());

//Result result = await ApplyUpdates(
// async (MerchantStatementAggregate merchantStatementAggregate) => {
// Need to rebuild the date time from the command as the Kind is Utc which is different from the date time used to generate the statement id
DateTime dt = new DateTime(command.RequestDto.MerchantStatementDate.Year, command.RequestDto.MerchantStatementDate.Month, command.RequestDto.MerchantStatementDate.Day);
Guid merchantStatementId = IdGenerationService.GenerateMerchantStatementAggregateId(command.EstateId, command.MerchantId, dt);

Result result = await ApplyUpdates(
async (MerchantStatementAggregate merchantStatementAggregate) =>

Check notice on line 176 in TransactionProcessor.BusinessLogic/Services/MerchantStatementDomainService.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

TransactionProcessor.BusinessLogic/Services/MerchantStatementDomainService.cs#L176

Remove the type specification; it is redundant.
{
MerchantStatement statement = merchantStatementAggregate.GetStatement();
List<(Guid merchantStatementForDateId, DateTime activityDate)> activityDates = statement.GetActivityDates();

// merchantStatementAggregate.GenerateStatement(DateTime.Now);
List<MerchantStatementForDate> statementForDateAggregates = new();
foreach ((Guid merchantStatementForDateId, DateTime activityDate) activityDate in activityDates)
{
Result<MerchantStatementForDateAggregate> statementForDateResult = await this.AggregateService.GetLatest<MerchantStatementForDateAggregate>(activityDate.merchantStatementForDateId, cancellationToken);
if (statementForDateResult.IsFailed)
return ResultHelpers.CreateFailure(statementForDateResult);
MerchantStatementForDate dailyStatement = statementForDateResult.Data.GetStatement(true);
statementForDateAggregates.Add(dailyStatement);
}

// Ok so now we have the daily statements we need to add a summary line to the statement aggregate
foreach (MerchantStatementForDate merchantStatementForDateAggregate in statementForDateAggregates)
{
// Build the summary event
var transactionsResult = merchantStatementForDateAggregate.GetStatementLines()
.Where(sl => sl.LineType == 1)
.Aggregate(new { Count = 0, TotalAmount = 0m },
(acc, sl) => new { Count = acc.Count + 1, TotalAmount = acc.TotalAmount + sl.Amount });
var settledFeesResult = merchantStatementForDateAggregate.GetStatementLines()
.Where(sl => sl.LineType == 2)
.Aggregate(new { Count = 0, TotalAmount = 0m },
(acc, sl) => new { Count = acc.Count + 1, TotalAmount = acc.TotalAmount + sl.Amount });
merchantStatementAggregate.AddDailySummaryRecord(merchantStatementForDateAggregate.ActivityDate, transactionsResult.Count, transactionsResult.TotalAmount, settledFeesResult.Count,
settledFeesResult.TotalAmount);
}

merchantStatementAggregate.GenerateStatement(DateTime.Now);

// return Result.Success();
// },
// command.EstateId, statementId, cancellationToken, false);
return Result.Success();
},
merchantStatementId, cancellationToken, false);

//if (result.IsFailed)
// return ResultHelpers.CreateFailure(result);
if (result.IsFailed)
return ResultHelpers.CreateFailure(result);

return Result.Success();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public record StatementEmailedEvent(Guid MerchantStatementId, Guid EstateId, Gui
public record StatementCreatedEvent(Guid MerchantStatementId, Guid EstateId, Guid MerchantId, DateTime StatementDate) : DomainEvent(MerchantStatementId, Guid.NewGuid());

public record ActivityDateAddedToStatementEvent(Guid MerchantStatementId, Guid EstateId, Guid MerchantId, Guid MerchantStatementForDateId, DateTime ActivityDate) : DomainEvent(MerchantStatementId, Guid.NewGuid());

public record StatementSummaryForDateEvent(Guid MerchantStatementId, Guid EstateId, Guid MerchantId, DateTime ActivityDate, Int32 LineNumber,
Int32 NumberOfTransactions, Decimal ValueOfTransactions, Int32 NumberOfSettledFees, Decimal ValueOfSettledFees) : DomainEvent(MerchantStatementId, Guid.NewGuid());
}

[ExcludeFromCodeCoverage]
Expand Down
Loading
Loading