using GB5Shared.DTO.Framework.Login; using GB5Shared.Resource.Response; using Microsoft.Extensions.Logging; using TCMSBLL.Interfaces; using TCMSDAL.DTO; using TCMSDAL.Interfaces; namespace TCMSBLL.Implementations; /// /// Business logic for MTCMSTESTCASE + MTCMSTESTSTEP. /// TC-ID auto-assignment: TC-[ModuleCode]-[SEQ] zero-padded to 3 digits, e.g. TC-INV-001. /// Steps are fully replaced on every save (delete+insert in DAL transaction). /// public class TCMSTestCaseBLL : ITCMSTestCaseBLL { private readonly ITCMSTestCaseDAL _Dal; private readonly ITCMSModuleDAL _ModuleDal; private readonly ILogger _Logger; public TCMSTestCaseBLL( ITCMSTestCaseDAL dal, ITCMSModuleDAL moduleDal, ILogger logger) { _Dal = dal; _ModuleDal = moduleDal; _Logger = logger; } public async Task GetTestCaseAsync( int testCaseId, LoginDTO login, CancellationToken ct) { var tc = await _Dal.GetTestCaseAsync(testCaseId, login, ct).ConfigureAwait(false); if (tc is null) return null; tc.Steps = (await _Dal.GetStepsAsync(testCaseId, login, ct).ConfigureAwait(false)).ToList(); return tc; } public async Task> GetTestCaseListAsync( int moduleId, string? priority, string? testType, string? status, bool? isActive, LoginDTO login, CancellationToken ct) => await _Dal.GetTestCaseListAsync(moduleId, priority, testType, status, isActive, login, ct).ConfigureAwait(false); public async Task> GetSelectListAsync( int moduleId, LoginDTO login, CancellationToken ct) => await _Dal.GetSelectListAsync(moduleId, login, ct).ConfigureAwait(false); public async Task SaveTestCaseAsync( TCMSTestCaseDTO dto, LoginDTO login, CancellationToken ct) { try { // Validation if (string.IsNullOrWhiteSpace(dto.Title)) return "Test Case Title is required."; if (dto.ModuleId == 0) return "Module is required."; bool isNew = dto.TestCaseId == 0; if (isNew) { // Auto-assign TC-ID var module = await _ModuleDal.GetModuleAsync(dto.ModuleId, login, ct).ConfigureAwait(false); if (module is null) return "Module not found."; string prefix = $"TC-{module.ModuleCode}"; int seq = await _Dal.GetNextSequenceAsync(prefix, login, ct).ConfigureAwait(false); dto.TcId = $"{prefix}-{seq:D3}"; int newId = await _Dal.SaveTestCaseAsync(dto, login, ct).ConfigureAwait(false); if (dto.Steps.Count > 0) await _Dal.SaveStepsAsync(newId, dto.Steps, login, ct).ConfigureAwait(false); return $"{SuccessResponse.SaveSuccessMessage} {newId}"; } else { await _Dal.UpdateTestCaseAsync(dto, login, ct).ConfigureAwait(false); // Always replace steps on update (even if empty — clears old steps) await _Dal.SaveStepsAsync(dto.TestCaseId, dto.Steps, login, ct).ConfigureAwait(false); return SuccessResponse.UpdateSuccess; } } catch (Exception ex) { _Logger.LogError(ex, "SaveTestCase failed for title {Title}", dto.Title); throw; } } public async Task DeleteTestCaseAsync( int testCaseId, LoginDTO login, CancellationToken ct) { try { await _Dal.DeleteTestCaseAsync(testCaseId, login.UserId, login, ct).ConfigureAwait(false); return SuccessResponse.DeleteSuccessMessage; } catch (Exception ex) { _Logger.LogError(ex, "DeleteTestCase failed for id {Id}", testCaseId); throw; } } }