Skip to content

Commit

Permalink
Merge pull request #180 from Brixel/feature/financial-years
Browse files Browse the repository at this point in the history
Feature/financial years
  • Loading branch information
vyruz1986 authored Jul 28, 2023
2 parents e25a1db + 8573cd7 commit 28f6ed2
Show file tree
Hide file tree
Showing 44 changed files with 2,221 additions and 118 deletions.
3 changes: 3 additions & 0 deletions Commands.Test/Commands.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

<ItemGroup>
<PackageReference Include="AutoMapper" Version="12.0.1" />
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.8" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.1" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
108 changes: 108 additions & 0 deletions Commands.Test/FinancialYear/When_adding_a_financial_year.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using Commands.Handlers.FinancialYear.AddFinancialYear;

using Domain;
using Domain.Interfaces;

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;

using Moq;

using Persistence;
using Persistence.Repositories;

using Xunit;

namespace Commands.Test.FinancialYear;

public class When_adding_a_financial_year
{
private readonly Mock<IFinancialYearRepository> _financialYearRepositoryMock;
private readonly HaSpManContext _haspmanDbContext;

public When_adding_a_financial_year()
{
_financialYearRepositoryMock = new Mock<IFinancialYearRepository>();

var financialYearConfigurationOptions = Options.Create(new FinancialYearConfiguration()
{
StartDate = new DateTimeOffset(new DateTime(2022,9,1)),
EndDate = new DateTimeOffset(new DateTime(2023,8,31))
});

_haspmanDbContext = new HaSpManContext(new DbContextOptionsBuilder<HaSpManContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options);
SUT = new AddFinancialYearHandler(_financialYearRepositoryMock.Object, financialYearConfigurationOptions,
_haspmanDbContext);
}

public AddFinancialYearHandler SUT { get; set; }




public class And_no_financial_year_already_exists : When_adding_a_financial_year
{
[Fact]
public async Task It_should_add_a_new_financial_year()
{
var startDate = new DateTimeOffset(new DateTime(DateTime.Now.Year, 9, 1));
var endDate = new DateTimeOffset(new DateTime(DateTime.Now.AddYears(1).Year, 8, 31));
_financialYearRepositoryMock
.Setup(x =>
x.Add(It.Is<Domain.FinancialYear>(financialYear => financialYear.StartDate == startDate)))
.Verifiable();
_financialYearRepositoryMock
.Setup(x =>
x.Add(It.Is<Domain.FinancialYear>(financialYear => financialYear.EndDate == endDate)))
.Verifiable();

await SUT.Handle(new AddFinancialYearCommand(), CancellationToken.None);

_financialYearRepositoryMock
.Verify(x =>
x.Add(It.Is<Domain.FinancialYear>(financialYear => financialYear.StartDate == startDate)));
_financialYearRepositoryMock
.Verify(x =>
x.Add(It.Is<Domain.FinancialYear>(financialYear => financialYear.EndDate == endDate)));

}


public class And_a_financial_year_already_exists : When_adding_a_financial_year
{
[Fact]
public async Task It_should_add_a_new_financial_year_following_the_last_year()
{

var startDate = new DateTimeOffset(new DateTime(2023, 9, 1));

var endDate = new DateTimeOffset(new DateTime(2024, 8, 31));
_financialYearRepositoryMock
.Setup(x =>
x.GetMostRecentAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(new Domain.FinancialYear(new DateTimeOffset(new DateTime(2022, 9, 1)),
new DateTimeOffset(new DateTime(2023,8,31)), new List<Domain.Transaction>()));

_financialYearRepositoryMock
.Setup(x =>
x.Add(It.Is<Domain.FinancialYear>(financialYear => financialYear.StartDate == startDate)))
.Verifiable();
_financialYearRepositoryMock
.Setup(x =>
x.Add(It.Is<Domain.FinancialYear>(financialYear => financialYear.EndDate == endDate)))
.Verifiable();

await SUT.Handle(new AddFinancialYearCommand(), CancellationToken.None);

_financialYearRepositoryMock
.Verify(x =>
x.Add(It.Is<Domain.FinancialYear>(financialYear => financialYear.StartDate == startDate)));
_financialYearRepositoryMock
.Verify(x =>
x.Add(It.Is<Domain.FinancialYear>(financialYear => financialYear.EndDate == endDate)));

}
}
}
}
74 changes: 74 additions & 0 deletions Commands.Test/FinancialYear/When_closing_a_financial_year.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Commands.Handlers.FinancialYear.CloseFinancialYear;

using Domain;
using Domain.Interfaces;

using FluentAssertions;

using Moq;

using Persistence.Repositories;

using Xunit;

namespace Commands.Test.FinancialYear;

public class When_closing_a_financial_year
{
private readonly Mock<IFinancialYearRepository> _financialYearRepositoryMock;

public When_closing_a_financial_year()
{
_financialYearRepositoryMock = new Mock<IFinancialYearRepository>();
SUT = new CloseFinancialYearHandler(_financialYearRepositoryMock.Object);
}

public CloseFinancialYearHandler SUT { get; set; }

[Fact]
public async Task It_should_mark_the_year_as_closed()
{
var startDate = DateTimeOffset.Now;
var financialYear = new Domain.FinancialYear(startDate, startDate.AddYears(1).AddDays(-1), new List<Domain.Transaction>());
_financialYearRepositoryMock
.Setup(x => x.GetByIdAsync(financialYear.Id, CancellationToken.None))
.ReturnsAsync(financialYear);
; await SUT.Handle(new CloseFinancialYearCommand(financialYear.Id), CancellationToken.None);

financialYear.IsClosed.Should().BeTrue();
}

[Fact]
public async Task It_should_mark_all_related_transactions_as_as_locked()
{
var startDate = DateTimeOffset.Now;
var financialYear = new Domain.FinancialYear(startDate, startDate.AddYears(1).AddDays(-1), new List<Domain.Transaction>()
{
new CreditTransaction("Random counter party", Guid.NewGuid(), 20,DateTimeOffset.Now, "A description", new List<TransactionAttachment>(), null, new List<TransactionTypeAmount>())
});
_financialYearRepositoryMock
.Setup(x => x.GetByIdAsync(financialYear.Id, CancellationToken.None))
.ReturnsAsync(financialYear);
;
await SUT.Handle(new CloseFinancialYearCommand(financialYear.Id), CancellationToken.None);

financialYear.IsClosed.Should().BeTrue();
}

[Fact]
public async Task It_should_throw_an_exception_when_no_year_is_found()
{
var newGuid = Guid.NewGuid();
var exception = await Assert.ThrowsAsync<ArgumentException>(async () =>
{
await SUT.Handle(new CloseFinancialYearCommand(newGuid), CancellationToken.None);
});
Assert.Equal($"No financial year found by Id {newGuid} (Parameter 'Id')", exception.Message);
}
}
62 changes: 62 additions & 0 deletions Commands.Test/Transaction/When_editing_a_transaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Commands.Handlers.Transaction.EditTransaction;

using Domain;
using Domain.Interfaces;

using FluentAssertions;

using MediatR;

using Moq;

using Persistence.Repositories;

using Xunit;

using AttachmentFile = Commands.Handlers.AttachmentFile;

namespace Commands.Test.Transaction;
public class When_editing_a_transaction
{
private readonly Mock<IFinancialYearRepository> _financialYearRepositoryMock;

public When_editing_a_transaction()
{
_financialYearRepositoryMock = new Mock<IFinancialYearRepository>();
var mediatorMock = new Mock<IMediator>();
SUT = new EditTransactionHandler(_financialYearRepositoryMock.Object, mediatorMock.Object);
}

public EditTransactionHandler SUT { get; set; }

[Fact]
public async Task It_should_throw_an_exception_when_locked()
{
var bankAccountId = Guid.NewGuid();

var transaction = new CreditTransaction("Random counter party", bankAccountId, 20m, DateTimeOffset.Now,
"A description", new List<TransactionAttachment>(), null, new List<TransactionTypeAmount>());
var financialYear = new Domain.FinancialYear(new DateTimeOffset(new DateTime(2022,9,1)), new DateTimeOffset(new DateTime(2023,8,31)), new List<Domain.Transaction>()
{
transaction
});
financialYear.Close();

_financialYearRepositoryMock
.Setup(x => x.GetFinancialYearByTransactionId(transaction.Id, CancellationToken.None))
.ReturnsAsync(financialYear);

var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await SUT.Handle(
new EditTransactionCommand(transaction.Id, "Random counter party name", null, bankAccountId,
DateTimeOffset.Now, "Another description", new List<TransactionTypeAmount>(),
new List<AttachmentFile>()), CancellationToken.None));

exception.Message.Should().Be("Financial year is already closed");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using FluentValidation;

namespace Commands.Handlers.FinancialYear.AddFinancialYear;

public record AddFinancialYearCommand() : IRequest<Domain.FinancialYear>;


public class AddFinancialYearCommandValidator : AbstractValidator<AddFinancialYearCommand>
{
public AddFinancialYearCommandValidator()
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Domain;
using Domain.Interfaces;

using Microsoft.Extensions.Options;

using Persistence;
using Persistence.Repositories;

namespace Commands.Handlers.FinancialYear.AddFinancialYear;

public class AddFinancialYearHandler : IRequestHandler<AddFinancialYearCommand, Domain.FinancialYear>
{
private readonly IFinancialYearRepository _financialYearRepository;
private readonly FinancialYearConfiguration _financialYearOptions;

private readonly HaSpManContext _haSpManContext;

public AddFinancialYearHandler(IFinancialYearRepository financialYearRepository,
IOptions<FinancialYearConfiguration> financialYearOptions,
HaSpManContext haSpManContext)
{
_financialYearRepository = financialYearRepository;
_financialYearOptions = financialYearOptions.Value;
_haSpManContext = haSpManContext;
}
public async Task<Domain.FinancialYear> Handle(AddFinancialYearCommand request, CancellationToken cancellationToken)
{

var lastFinancialYear = await _financialYearRepository.GetMostRecentAsync(cancellationToken);

// In case this is the first year we create, assume we want it to be this year.
// Otherwise, just add a new year
var year = lastFinancialYear == null ? DateTime.Now.Year : lastFinancialYear.EndDate.Year;

var startDate = new DateTimeOffset(new DateTime(year, _financialYearOptions.StartDate.Month, _financialYearOptions.StartDate.Day));

var financialYear = new Domain.FinancialYear(
startDate,
startDate.AddYears(1).AddDays(-1),
new List<Domain.Transaction>());

_financialYearRepository.Add(financialYear);
await _financialYearRepository.SaveChangesAsync(cancellationToken);
return financialYear;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using FluentValidation;

namespace Commands.Handlers.FinancialYear.CloseFinancialYear;

public record CloseFinancialYearCommand(Guid Id) : IRequest;

public class CloseFinancialYearCommandValidator : AbstractValidator<CloseFinancialYearCommand>
{
public CloseFinancialYearCommandValidator()
{
RuleFor(x => x.Id).NotEmpty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Domain.Interfaces;

using Persistence.Repositories;

namespace Commands.Handlers.FinancialYear.CloseFinancialYear;

public class CloseFinancialYearHandler : IRequestHandler<CloseFinancialYearCommand>
{
private readonly IFinancialYearRepository _financialYearRepository;

public CloseFinancialYearHandler(IFinancialYearRepository financialYearRepository)
{
_financialYearRepository = financialYearRepository;
}
public async Task Handle(CloseFinancialYearCommand request, CancellationToken cancellationToken)
{
var financialYear = await _financialYearRepository.GetByIdAsync(request.Id, cancellationToken)
?? throw new ArgumentException($"No financial year found by Id {request.Id}", nameof(request.Id));
financialYear.Close();

await _financialYearRepository.SaveChangesAsync(cancellationToken);

}
}
Loading

0 comments on commit 28f6ed2

Please sign in to comment.