Distribution_GL Initialization
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
using General_Ledger_Service.DTOs.Common;
|
||||
using General_Ledger_Service.DTOs.CostCenters;
|
||||
using General_Ledger_Service.Enums;
|
||||
using General_Ledger_Service.Exceptions;
|
||||
using General_Ledger_Service.Infra.UoW;
|
||||
using General_Ledger_Service.Interfaces.Repositories;
|
||||
using General_Ledger_Service.Interfaces.Services;
|
||||
using General_Ledger_Service.Models;
|
||||
|
||||
namespace General_Ledger_Service.Services
|
||||
{
|
||||
public class CostCenterService(
|
||||
ICostCenterRepository costCenterRepository,
|
||||
ISystemConfigRepository systemConfigRepository,
|
||||
IAuditLogRepository auditLogRepository,
|
||||
IUnitOfWork unitOfWork) : ICostCenterService
|
||||
{
|
||||
private readonly ICostCenterRepository _costCenterRepository = costCenterRepository;
|
||||
private readonly ISystemConfigRepository _systemConfigRepository = systemConfigRepository;
|
||||
private readonly IAuditLogRepository _auditLogRepository = auditLogRepository;
|
||||
private readonly IUnitOfWork _unitOfWork = unitOfWork;
|
||||
|
||||
public async Task<ApiResponse> CreateCostCenterAsync(CreateCostCenterRequest request)
|
||||
{
|
||||
CostCenter? parent = null;
|
||||
|
||||
if (request.ParentCostCenterId.HasValue)
|
||||
{
|
||||
parent = await _costCenterRepository.GetByIdAsync(request.ParentCostCenterId.Value)
|
||||
?? throw new NotFoundException("Parent cost center not found");
|
||||
|
||||
var resultingDepth = await _costCenterRepository.GetAncestorDepthAsync(parent.CostCenterId);
|
||||
await DepthGuard.EnsureWithinMaxDepthAsync(
|
||||
_systemConfigRepository, "COST_CENTER_MAX_DEPTH", null, resultingDepth, "Maximum Cost Center depth exceeded");
|
||||
}
|
||||
|
||||
var code = await GenerateCostCenterCodeAsync(parent);
|
||||
|
||||
var costCenter = new CostCenter
|
||||
{
|
||||
Code = code,
|
||||
Name = request.Name,
|
||||
ParentCostCenterId = request.ParentCostCenterId,
|
||||
IsActive = request.IsActive
|
||||
};
|
||||
|
||||
await _unitOfWork.BeginAsync();
|
||||
try
|
||||
{
|
||||
await _costCenterRepository.AddAsync(costCenter);
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
await _auditLogRepository.AddAsync(new AuditLog
|
||||
{
|
||||
Category = AuditCategory.Administrative,
|
||||
EntityName = "CostCenter",
|
||||
EntityId = costCenter.CostCenterId.ToString(),
|
||||
Action = AuditAction.Create,
|
||||
Description = $"Cost center {costCenter.Code} created",
|
||||
PerformedBy = null
|
||||
});
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
await _unitOfWork.CommitAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _unitOfWork.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
|
||||
return ResponseHelpers.Created("Cost center created successfully", costCenter);
|
||||
}
|
||||
|
||||
private async Task<string> GenerateCostCenterCodeAsync(CostCenter? parent)
|
||||
{
|
||||
if (parent != null)
|
||||
{
|
||||
for (var suffix = 1; suffix <= 99; suffix++)
|
||||
{
|
||||
var code = $"{parent.Code}-{suffix:D2}";
|
||||
if (await _costCenterRepository.GetByCodeAsync(code) is null)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
throw new BadRequestException("Maximum number of child cost centers under this parent has been reached.");
|
||||
}
|
||||
|
||||
// Probes each candidate slot directly (same fix as AccountService.GenerateAccountCodeAsync)
|
||||
// rather than trusting a root count, so a pre-existing, manually-coded cost center can
|
||||
// never collide with a generated one.
|
||||
for (var slot = 1; slot <= 999; slot++)
|
||||
{
|
||||
var code = $"CC-{slot:D3}";
|
||||
if (await _costCenterRepository.GetByCodeAsync(code) is null)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
throw new BadRequestException("Maximum number of root-level cost centers has been reached.");
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetCostCenterByCodeAsync(string costCenterCode, string? expand)
|
||||
{
|
||||
var costCenter = await _costCenterRepository.GetByCodeAsync(costCenterCode)
|
||||
?? throw new NotFoundException("Cost center not found");
|
||||
|
||||
var breadcrumb = await _costCenterRepository.GetAncestorBreadcrumbAsync(costCenter.CostCenterId);
|
||||
|
||||
List<CostCenterTreeNode>? descendantTree = null;
|
||||
if (string.Equals(expand, "tree", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
descendantTree = await _costCenterRepository.GetDescendantTreeAsync(costCenter.CostCenterId);
|
||||
}
|
||||
|
||||
var data = new CostCenterDetailResponse
|
||||
{
|
||||
CostCenter = costCenter,
|
||||
AncestorBreadcrumb = breadcrumb,
|
||||
DescendantTree = descendantTree
|
||||
};
|
||||
|
||||
return ResponseHelpers.Ok("Cost center retrieved successfully", data);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user