Distribution_GL Initialization
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
using General_Ledger_Service.Exceptions;
|
||||
using General_Ledger_Service.Interfaces.Repositories;
|
||||
using General_Ledger_Service.Models;
|
||||
|
||||
namespace General_Ledger_Service.Services
|
||||
{
|
||||
// Extracted from AccountService (2026-07-31) so BankService's auto-created "Bank"/"Cash" GL
|
||||
// hierarchy (see BankService.CreateBankAccountAsync/CreateCashAccountAsync) can reuse the same
|
||||
// Rule 8.1 code-generation scheme instead of duplicating it - same shared-static-helper shape
|
||||
// as RecursiveTreeQueries/DepthGuard (CLAUDE.md Rule 11), not a base class.
|
||||
public static class AccountCodeGenerator
|
||||
{
|
||||
private static readonly Dictionary<short, int> AccountTypeBlockStart = new()
|
||||
{
|
||||
[1] = 1000, // Asset
|
||||
[2] = 2000, // Liability
|
||||
[3] = 3000, // Equity
|
||||
[4] = 4000, // Income
|
||||
[5] = 5000 // Expense
|
||||
};
|
||||
|
||||
public static async Task<string> GenerateAsync(IAccountRepository accountRepository, short accountTypeId, Account? parent)
|
||||
{
|
||||
if (parent != null)
|
||||
{
|
||||
for (var suffix = 1; suffix <= 99; suffix++)
|
||||
{
|
||||
var code = $"{parent.AccountCode}-{suffix:D2}";
|
||||
|
||||
if (code.Length > 20)
|
||||
{
|
||||
throw new BadRequestException("Cannot generate an account code: nesting is too deep for the 20-character account code column.");
|
||||
}
|
||||
|
||||
if (await accountRepository.GetByCodeAsync(code) is null)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
throw new BadRequestException("Maximum number of child accounts under this parent has been reached.");
|
||||
}
|
||||
|
||||
if (!AccountTypeBlockStart.TryGetValue(accountTypeId, out var blockStart))
|
||||
{
|
||||
throw new BadRequestException(
|
||||
$"Invalid accountTypeId '{accountTypeId}'. Must be one of: 1 (Asset), 2 (Liability), 3 (Equity), 4 (Income), 5 (Expense).");
|
||||
}
|
||||
|
||||
// Probes each of the 10 designed slots directly rather than trusting a root count,
|
||||
// since pre-existing accounts created before this generation scheme existed (manually
|
||||
// coded, e.g. "5100") don't necessarily occupy slots in count order - a count-based
|
||||
// guess can collide with one of those and crash on the DB's unique constraint instead
|
||||
// of failing cleanly.
|
||||
for (var slot = 0; slot < 10; slot++)
|
||||
{
|
||||
var code = (blockStart + slot * 100).ToString();
|
||||
if (await accountRepository.GetByCodeAsync(code) is null)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
throw new BadRequestException("Maximum number of root-level accounts for this account type has been reached.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user