using General_Ledger_Service.DTOs.Common; using General_Ledger_Service.DTOs.SystemConfig; 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 SystemConfigService( ISystemConfigRepository systemConfigRepository, IAuditLogRepository auditLogRepository, IUnitOfWork unitOfWork) : ISystemConfigService { // Per-key audit classification (CLAUDE.md Rule 10 / Document 1 Section 4.3) - a // future purely-cosmetic key must not silently inherit Ledger, so anything not // listed here defaults to Administrative rather than Ledger. private static readonly Dictionary KeyCategories = new(StringComparer.OrdinalIgnoreCase) { ["COA_MAX_DEPTH"] = AuditCategory.Ledger, ["COST_CENTER_MAX_DEPTH"] = AuditCategory.Ledger, ["COA_ENFORCE_MAX_DEPTH"] = AuditCategory.Ledger, ["CASH_ACCOUNT_ROOT_ID"] = AuditCategory.Ledger, ["CORPORATE_INCOME_TAX_RATE"] = AuditCategory.Ledger, ["STATUTORY_RELIEF_AMOUNT"] = AuditCategory.Ledger, ["APIT_CREDIT_ACCOUNT_ID"] = AuditCategory.Ledger, ["WHT_CREDIT_ACCOUNT_ID"] = AuditCategory.Ledger, ["QUARTERLY_TAX_PAYMENT_ACCOUNT_ID"] = AuditCategory.Ledger }; private readonly ISystemConfigRepository _systemConfigRepository = systemConfigRepository; private readonly IAuditLogRepository _auditLogRepository = auditLogRepository; private readonly IUnitOfWork _unitOfWork = unitOfWork; public async Task UpdateAsync(string key, UpdateSystemConfigRequest request) { var config = await _systemConfigRepository.GetByKeyAsync(key) ?? throw new NotFoundException("System config key not found"); if (!config.IsEditable || config.IsLocked) { throw new BadRequestException($"System config key '{key}' cannot be edited"); } config.ConfigValue = request.ConfigValue; config.IsLocked = true; var category = KeyCategories.TryGetValue(key, out var mappedCategory) ? mappedCategory : AuditCategory.Administrative; await _unitOfWork.BeginAsync(); try { await _unitOfWork.SaveChangesAsync(); await _auditLogRepository.AddAsync(new AuditLog { Category = category, EntityName = "SystemConfig", EntityId = key, Action = AuditAction.Update, Description = $"System config {key} updated", PerformedBy = null }); await _unitOfWork.SaveChangesAsync(); await _unitOfWork.CommitAsync(); } catch { await _unitOfWork.RollbackAsync(); throw; } return ResponseHelpers.Ok("System config updated successfully", config); } public async Task ListAsync() { var configs = await _systemConfigRepository.GetAllAsync(); return ResponseHelpers.Ok("System config retrieved successfully", configs); } } }