Skip to content

Commit

Permalink
Classification lvl + unique account_group code per classification. (n…
Browse files Browse the repository at this point in the history
…eed to be more tested)
  • Loading branch information
fdonnet committed Oct 19, 2023
1 parent a94b445 commit 5ad22a9
Show file tree
Hide file tree
Showing 23 changed files with 232 additions and 31 deletions.
4 changes: 3 additions & 1 deletion src/Ubik.Accounting.Api/Data/AccountingContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public AccountingContext(DbContextOptions<AccountingContext> options, ICurrentUs

public DbSet<Account> Accounts { get; set; }
public DbSet<AccountGroup> AccountGroups { get; set; }
public DbSet<AccountGroupClassification> AccountGroupClassifications { get; set; }
public DbSet<Currency> Currencies { get; set; }
public DbSet<Entry> Entries { get; set; }
public DbSet<TaxRate> TaxRates { get; set; }
Expand All @@ -36,8 +37,9 @@ public override async Task<int> SaveChangesAsync(CancellationToken cancellationT

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
new AccountConfiguration().Configure(modelBuilder.Entity<Account>());
new AccountGroupClassificationConfiguration().Configure(modelBuilder.Entity<AccountGroupClassification>());
new AccountGroupConfiguration().Configure(modelBuilder.Entity<AccountGroup>());
new AccountConfiguration().Configure(modelBuilder.Entity<Account>());

modelBuilder.Entity<Entry>()
.HasOne(s => s.MainEntry)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
using Ubik.Accounting.Api.Models;

namespace Ubik.Accounting.Api.Data.Config
{
public class AccountGroupClassificationConfiguration : IEntityTypeConfiguration<AccountGroupClassification>
{
public void Configure(EntityTypeBuilder<AccountGroupClassification> builder)
{
builder.ToTable("AccountGroupClassifications");

builder.Property(a => a.Code)
.IsRequired()
.HasMaxLength(20);

builder.Property(a => a.Label)
.IsRequired()
.HasMaxLength(100);

builder.Property(a => a.Description)
.HasMaxLength(700);

builder.Property(a => a.Version)
.IsConcurrencyToken();

builder.Property(a => a.TenantId)
.IsRequired();

builder.Property(a => a.CreatedAt)
.IsRequired();

builder.Property(a => a.CreatedBy)
.IsRequired();

builder.HasIndex(a => a.Code)
.IsUnique();

builder.HasIndex(a => a.TenantId);

//TODO: Change that quick with userservice
builder
.HasQueryFilter(a => a.TenantId == Guid.Parse("727449e8-e93c-49e6-a5e5-1bf145d3e62d"));

builder
.HasOne(a => a.CreatedByUser)
.WithMany()
.HasForeignKey(b => b.CreatedBy)
.IsRequired(true);

builder
.HasOne(a => a.ModifiedByUser)
.WithMany()
.HasForeignKey(b => b.ModifiedBy)
.IsRequired(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public void Configure(EntityTypeBuilder<AccountGroup> builder)
builder.Property(a => a.CreatedBy)
.IsRequired();

builder.HasIndex(a => a.Code)
builder.HasIndex(a => new { a.Code, a.AccountGroupClassificationId })
.IsUnique();

builder.HasIndex(a => a.TenantId);
Expand All @@ -59,6 +59,12 @@ public void Configure(EntityTypeBuilder<AccountGroup> builder)
.WithMany()
.HasForeignKey(b => b.ModifiedBy)
.IsRequired(false);

builder
.HasOne(a => a.AccountGroupClassification)
.WithMany(g => g.OwnedAccountGroups)
.HasForeignKey(b => b.AccountGroupClassificationId)
.IsRequired(true);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Ubik.Accounting.Api.Models;

namespace Ubik.Accounting.Api.Data.Init
{
internal static class AccountGroupClassificationsData
{
internal static void Load(AccountingContext context)
{
if (!context.AccountGroupClassifications.Any())
{
var baseValuesGeneral = new BaseValuesGeneral();
var baseValuesForTenants = new BaseValuesForTenants();
var baseValuesForUsers = new BaseValuesForUsers();
var baseValuesForAccountGroupClassifications = new BaseValuesForAccountGroupClassifications();
var accountGroupClassifications = new AccountGroupClassification[]
{
new AccountGroupClassification
{
Id = baseValuesForAccountGroupClassifications.AccountGroupClassificationId1,
CreatedBy = baseValuesForUsers.UserId1,
CreatedAt = baseValuesGeneral.GenerationTime,
Code = "SWISSPLAN",
Description = "Plan comptable suisse",
Label = "Test",
ModifiedBy = baseValuesForUsers.UserId1,
ModifiedAt = baseValuesGeneral.GenerationTime,
Version = Guid.NewGuid(),
TenantId = baseValuesForTenants.TenantId
},
new AccountGroupClassification
{
Id = baseValuesForAccountGroupClassifications.AccountGroupClassificationId2,
CreatedBy = baseValuesForUsers.UserId1,
CreatedAt = baseValuesGeneral.GenerationTime,
Code = "SWISSPLAN2",
Description = "Plan comptable suisse2",
Label = "Test",
ModifiedBy = baseValuesForUsers.UserId1,
ModifiedAt = baseValuesGeneral.GenerationTime,
Version = Guid.NewGuid(),
TenantId = baseValuesForTenants.TenantId
}
};

foreach (AccountGroupClassification cl in accountGroupClassifications)
{
context.AccountGroupClassifications.Add(cl);
}
context.SaveChanges();
}
}
}
}
5 changes: 5 additions & 0 deletions src/Ubik.Accounting.Api/Data/Init/AccountGroupsData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal static void Load(AccountingContext context)
var baseValuesForTenants = new BaseValuesForTenants();
var baseValuesForUsers = new BaseValuesForUsers();
var baseValuesForAccountGroups = new BaseValuesForAccountGroups();
var baseValuesForAccountGroupClassifications = new BaseValuesForAccountGroupClassifications();
var accountGroups = new AccountGroup[]
{
new AccountGroup
Expand All @@ -24,6 +25,7 @@ internal static void Load(AccountingContext context)
Label = "Liquidités",
ModifiedBy = baseValuesForUsers.UserId1,
ModifiedAt = baseValuesGeneral.GenerationTime,
AccountGroupClassificationId = baseValuesForAccountGroupClassifications.AccountGroupClassificationId1,
ParentAccountGroupId = null,
Version = Guid.NewGuid(),
TenantId = baseValuesForTenants.TenantId
Expand All @@ -38,6 +40,7 @@ internal static void Load(AccountingContext context)
Label = "Banques",
ModifiedBy = baseValuesForUsers.UserId1,
ModifiedAt = baseValuesGeneral.GenerationTime,
AccountGroupClassificationId = baseValuesForAccountGroupClassifications.AccountGroupClassificationId1,
ParentAccountGroupId = baseValuesForAccountGroups.AccountGroupIdFirstLvl1,
Version = Guid.NewGuid(),
TenantId = baseValuesForTenants.TenantId
Expand All @@ -52,6 +55,7 @@ internal static void Load(AccountingContext context)
Label = "Autres",
ModifiedBy = baseValuesForUsers.UserId1,
ModifiedAt = baseValuesGeneral.GenerationTime,
AccountGroupClassificationId = baseValuesForAccountGroupClassifications.AccountGroupClassificationId2,
ParentAccountGroupId = baseValuesForAccountGroups.AccountGroupIdFirstLvl1,
Version = Guid.NewGuid(),
TenantId = baseValuesForTenants.TenantId
Expand All @@ -66,6 +70,7 @@ internal static void Load(AccountingContext context)
Label = "To be removed Autres actifs",
ModifiedBy = baseValuesForUsers.UserId1,
ModifiedAt = baseValuesGeneral.GenerationTime,
AccountGroupClassificationId = baseValuesForAccountGroupClassifications.AccountGroupClassificationId1,
ParentAccountGroupId = baseValuesForAccountGroups.AccountGroupIdFirstLvl1,
Version = Guid.NewGuid(),
TenantId = baseValuesForTenants.TenantId
Expand Down
8 changes: 8 additions & 0 deletions src/Ubik.Accounting.Api/Data/Init/BaseValues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ public record BaseValuesForAccountGroups
public string AccountGroupCode1 { get; } = "102";
}

public record BaseValuesForAccountGroupClassifications
{
public Guid AccountGroupClassificationId1 { get; } = Guid.Parse("1524f188-20dd-4888-88f8-428e59bbc22a");
public Guid AccountGroupClassificationId2 { get; } = Guid.Parse("1524f189-20dd-4888-88f8-428e59bbc22a");
public Guid AccountGroupClassificationIdForDel { get; } = Guid.Parse("1524f190-20dd-4888-88f8-428e59bbc22c");
public string AccountGroupClassificationCode1 { get; } = "SWISSPLAN";
}

public record BaseValuesForTenants
{
public Guid TenantId { get; } = Guid.Parse("727449e8-e93c-49e6-a5e5-1bf145d3e62d");
Expand Down
1 change: 1 addition & 0 deletions src/Ubik.Accounting.Api/Data/Init/DbInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class DbInitializer
public void Initialize(AccountingContext context)
{
UsersData.Load(context);
AccountGroupClassificationsData.Load(context);
AccountGroupsData.Load(context);
AccountsData.Load(context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ public async Task<IEnumerable<AccountGroup>> GetAllAsync()
return accountGroups;
}

public async Task<bool> IfExistsAsync(string accountGroupCode)
public async Task<bool> IfExistsAsync(string accountGroupCode,Guid accountGroupClassificationId)
{
return await _context.AccountGroups.AnyAsync(a => a.Code == accountGroupCode);
return await _context.AccountGroups.AnyAsync(a => a.Code == accountGroupCode
&& a.AccountGroupClassificationId == accountGroupClassificationId);
}

public async Task<bool> HasAnyChildAccountGroups(Guid Id)
Expand All @@ -62,9 +63,12 @@ public async Task<bool> IfExistsAsync(Guid accountGroupId)
return await _context.AccountGroups.AnyAsync(a => a.Id == accountGroupId);
}

public async Task<bool> IfExistsWithDifferentIdAsync(string accountGroupCode, Guid currentId)
public async Task<bool> IfExistsWithDifferentIdAsync(string accountGroupCode, Guid accountGroupClassificationId, Guid currentId)
{
return await _context.AccountGroups.AnyAsync(a => a.Code == accountGroupCode && a.Id != currentId);
return await _context.AccountGroups.AnyAsync(a => a.Code == accountGroupCode
&& a.AccountGroupClassificationId == accountGroupClassificationId
&& a.Id != currentId);

}

public async Task<AccountGroup> UpdateAsync(AccountGroup accountGroup)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public record AddAccountGroupCommand : IRequest<AddAccountGroupResult>
public string Label { get; set; } = default!;
public string? Description { get; set; }
public Guid? ParentAccountGroupId { get; set; }
public Guid AccountGroupClassificationId { get; set; }
}

//Output
Expand All @@ -24,6 +25,7 @@ public record AddAccountGroupResult
public string Label { get; set; } = default!;
public string? Description { get; set; }
public Guid? ParentAccountGroupId { get; set; }
public Guid AccountGroupClassificationId { get; set; }
public Guid Version { get; set; }
}

Expand All @@ -38,14 +40,18 @@ public async Task<AddAccountGroupResult> Handle(AddAccountGroupCommand request,
{
var accountGroup = request.ToAccountGroup();

var accountGroupExists = await _serviceManager.AccountGroupService.IfExistsAsync(accountGroup.Code);
var accountGroupExists = await _serviceManager.AccountGroupService
.IfExistsAsync(accountGroup.Code, accountGroup.AccountGroupClassificationId);

if (accountGroupExists)
throw new AccountGroupAlreadyExistsException(request.Code);
throw new AccountGroupAlreadyExistsException(request.Code,request.AccountGroupClassificationId);

//Check if parent account group exists
if(accountGroup.ParentAccountGroupId != null)
{
var parentAccountExists = await _serviceManager.AccountGroupService.IfExistsAsync((Guid)accountGroup.ParentAccountGroupId);
var parentAccountExists = await _serviceManager.AccountGroupService
.IfExistsAsync((Guid)accountGroup.ParentAccountGroupId);

if (!parentAccountExists)
throw new AccountGroupParentNotFoundException((Guid)accountGroup.ParentAccountGroupId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public AddAccountGroupValidator()

RuleFor(command => command.Description)
.MaximumLength(700).WithMessage("Description must be 700 characters max.");

RuleFor(command => command.AccountGroupClassificationId)
.NotEmpty().WithMessage("AccountGroupClassificationId is required");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public record UpdateAccountGroupCommand : IRequest<UpdateAccountGroupResult>
public string Label { get; set; } = default!;
public string? Description { get; set; }
public Guid? ParentAccountGroupId { get; set; }
public Guid AccountGroupClassificationId { get; set; }
public Guid Version { get; set; }
}

Expand All @@ -27,6 +28,7 @@ public record UpdateAccountGroupResult
public string Label { get; set; } = default!;
public string? Description { get; set; }
public Guid? ParentAccountGroupId { get; set; }
public Guid AccountGroupClassificationId { get; set; }
public Guid Version { get; set; }
}

Expand All @@ -42,9 +44,11 @@ public UpdateAccountGroupHandler(IServiceManager serviceManager)
public async Task<UpdateAccountGroupResult> Handle(UpdateAccountGroupCommand request, CancellationToken cancellationToken)
{
//Check if the account group code already exists in other records
var alreadyExistsWithOtherId = await _serviceManager.AccountGroupService.IfExistsWithDifferentIdAsync(request.Code, request.Id);
var alreadyExistsWithOtherId = await _serviceManager.AccountGroupService
.IfExistsWithDifferentIdAsync(request.Code, request.AccountGroupClassificationId, request.Id);

if (alreadyExistsWithOtherId)
throw new AccountGroupAlreadyExistsException(request.Code);
throw new AccountGroupAlreadyExistsException(request.Code,request.AccountGroupClassificationId);

//Check if the account group is found
var accountGroup = await _serviceManager.AccountGroupService.GetAsync(request.Id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public UpdateAccountGroupValidator()

RuleFor(command => command.Version)
.NotEmpty().WithMessage("Version is required. Need to be checked for concurrency updates.");

RuleFor(command => command.AccountGroupClassificationId)
.NotEmpty().WithMessage("AccountGroupClassificationId is required");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ public class AccountGroupAlreadyExistsException : Exception, IServiceAndFeatureE
public ServiceAndFeatureExceptionType ErrorType { get; init; }
public List<CustomError> CustomErrors { get; init; }

public AccountGroupAlreadyExistsException(string codeAlreadyExisting)
public AccountGroupAlreadyExistsException(string codeAlreadyExisting, Guid accountGroupClassification)
: base($"An account group with this code: {codeAlreadyExisting} already exists.")
{

ErrorType = ServiceAndFeatureExceptionType.Conflict;
CustomErrors = new List<CustomError>() { new CustomError()
{
ErrorCode = "ACCOUNTGROUP_ALREADY_EXISTS",
ErrorFriendlyMessage = "The account group already exists. Code field needs to be unique.",
ErrorValueDetails = $"Field:Code / Value:{codeAlreadyExisting}"
ErrorFriendlyMessage = "The account group already exists. Code field needs to be unique in a group classification.",
ErrorValueDetails = $"Field:Code|AccountGroupClassificationId / Value:{codeAlreadyExisting}|{accountGroupClassification}"
}};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ public interface IAccountGroupService
{
public Task<IEnumerable<AccountGroup>> GetAllAsync();
public Task<AccountGroup?> GetAsync(Guid id);
public Task<bool> IfExistsAsync(string accountGroupCode);
public Task<bool> IfExistsAsync(string accountGroupCode, Guid accountGroupClassificationId);
public Task<bool> IfExistsAsync(Guid accountGroupId);
public Task<bool> IfExistsWithDifferentIdAsync(string accountGroupCode, Guid currentId);
public Task<bool> IfExistsWithDifferentIdAsync(string accountGroupCode,
Guid accountGroupClassificationId, Guid currentId);

public Task<bool> HasAnyChildAccountGroups(Guid Id);
public Task<bool> HasAnyChildAccounts(Guid Id);
public Task<AccountGroup> AddAsync(AccountGroup accountGroup);
Expand Down
Loading

0 comments on commit 5ad22a9

Please sign in to comment.