using System; using System.ComponentModel.DataAnnotations; using System.Threading; using System.Threading.Tasks; using RecruitmentDAL.DTO.SelectionProcess; using GB5Shared.DaprCache; using GB5Shared.DTO.Framework.AutoNumber; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.EntityHandler; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using GB5Shared.Telemetry; using GB5Shared.Validation; using Microsoft.Extensions.Logging; using RecruitmentDAL.CustomeCode.SelectionProcess; using static GB5Shared.GB5Constant.Constant; namespace RecruitmentBLL.SelectionProcess { public class SelectionProcessBLL : ISelectionProcessBLL { private readonly ISelectionProcessDAL _SelectionProcessDAL; private readonly AutoNumber _AutoNumber; private readonly IValidation _Validation; private readonly KeyInvalidate _KeyInvalidate; private readonly BaseEntityAppService _BaseEntityAppService; private readonly BaseEntityAppService _BaseEntityAppServiceStage; private readonly ILogger _Logger; public SelectionProcessBLL( ISelectionProcessDAL selectionProcessDAL, AutoNumber autoNumber, IValidation validation, KeyInvalidate keyInvalidate, BaseEntityAppService baseEntityAppService, BaseEntityAppService baseEntityAppServiceStage, ILogger logger) { _SelectionProcessDAL = selectionProcessDAL; _AutoNumber = autoNumber; _Validation = validation; _KeyInvalidate = keyInvalidate; _BaseEntityAppService = baseEntityAppService; _BaseEntityAppServiceStage = baseEntityAppServiceStage; _Logger = logger; } #region Get public async Task GetSelectionProcessTemplate(int SelectionProcessTemplateId, LoginDTO LoginDTO, CancellationToken ct) { try { return await _SelectionProcessDAL.GetSelectionProcessTemplate(SelectionProcessTemplateId, LoginDTO, ct) .ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-selectionprocesstemplate-failed", ex); _Logger.LogError(ex, "GetSelectionProcessTemplate failed for SelectionProcessTemplateId {SelectionProcessTemplateId}", SelectionProcessTemplateId); throw; } } #endregion #region Save public async Task SaveSelectionProcessTemplate(SelectionProcessTemplateDTO SelectionProcessTemplateDTO, LoginDTO LoginDTO, CancellationToken ct) { if (SelectionProcessTemplateDTO == null) throw new ArgumentNullException(nameof(SelectionProcessTemplateDTO)); AutoNumberDTO? autoNumberDTO = null; try { GB5Trace.Step("validate-selectionprocesstemplate", new { SelectionProcessTemplateDTO.SelectionProcessTemplateId }); await _Validation.NotEmpty( SelectionProcessTemplateDTO.TemplateName, nameof(SelectionProcessTemplateDTO.TemplateName)).ConfigureAwait(false); await _Validation.NotEmpty( SelectionProcessTemplateDTO.TemplateCode, nameof(SelectionProcessTemplateDTO.TemplateCode)).ConfigureAwait(false); bool isNew = SelectionProcessTemplateDTO.SelectionProcessTemplateId == 0; SelectionProcessTemplateDTO.TenantId = LoginDTO.ClientId; SelectionProcessTemplateDTO.ModifiedById = LoginDTO.UserId; SelectionProcessTemplateDTO.ModifiedOn = DateTime.UtcNow; if (isNew) { autoNumberDTO = await _AutoNumber.GetNumberAsync( 1, "SELECTIONPROCESSTEMPLATE", LoginDTO).ConfigureAwait(false); SelectionProcessTemplateDTO.SelectionProcessTemplateId = autoNumberDTO.StartNumber; SelectionProcessTemplateDTO.CreatedById = LoginDTO.UserId; SelectionProcessTemplateDTO.CreatedOn = DateTime.UtcNow; if (SelectionProcessTemplateDTO.Status == 0) SelectionProcessTemplateDTO.Status = 1; } GB5Trace.Step("save-selectionprocesstemplate", new { SelectionProcessTemplateDTO.SelectionProcessTemplateId, isNew }); await _BaseEntityAppService.ExecuteSaveAsync( EntityConstant.OBJECTRECRUITMENTSELECTIONPROCESSTEMPLATE, isNew ? EventTypeConstant.SAVERECRUITMENTSELECTIONPROCESSTEMPLATEEVENTTYPEID : EventTypeConstant.UPDATERECRUITMENTSELECTIONPROCESSTEMPLATEEVENTTYPEID, SelectionProcessTemplateDTO, LoginDTO, async tx => { _ = isNew ? await _SelectionProcessDAL.SaveSelectionProcessTemplate(SelectionProcessTemplateDTO, LoginDTO, tx, ct).ConfigureAwait(false) : await _SelectionProcessDAL.UpdateSelectionProcessTemplate(SelectionProcessTemplateDTO, LoginDTO, tx, ct).ConfigureAwait(false); return SelectionProcessTemplateDTO.SelectionProcessTemplateId; }, null, -1, -1, null, isNew).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeId = isNew ? EventTypeConstant.SAVERECRUITMENTSELECTIONPROCESSTEMPLATEEVENTTYPEID : EventTypeConstant.UPDATERECRUITMENTSELECTIONPROCESSTEMPLATEEVENTTYPEID }); var cacheKey = new CacheKeyGeneration().KeyGeneration( SelectionProcessTemplateDTO.SelectionProcessTemplateId, EntityConstant.OBJECTRECRUITMENTSELECTIONPROCESSTEMPLATE, CacheKeyLevel.CLIENT_LEVEL, LoginDTO); await _KeyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); _Logger.LogInformation( "SelectionProcessTemplate {SelectionProcessTemplateId} {Action} by user {UserId}", SelectionProcessTemplateDTO.SelectionProcessTemplateId, isNew ? "saved" : "updated", LoginDTO.UserId); return isNew ? $"{SuccessResponse.SaveSuccessMessage} {SelectionProcessTemplateDTO.SelectionProcessTemplateId}" : $"{SuccessResponse.UpdateSuccessMessage} {SelectionProcessTemplateDTO.SelectionProcessTemplateId}"; } catch (ValidationException vex) { GB5Trace.MarkFailed("save-selectionprocesstemplate-failed", vex); if (autoNumberDTO != null && SelectionProcessTemplateDTO.SelectionProcessTemplateId > 0) await _AutoNumber.RollbackAutoNumber("SELECTIONPROCESSTEMPLATE", SelectionProcessTemplateDTO.SelectionProcessTemplateId, LoginDTO).ConfigureAwait(false); throw new Exception(vex.Message); } catch (Exception ex) { GB5Trace.MarkFailed("save-selectionprocesstemplate-failed", ex); _Logger.LogError(ex, "SaveSelectionProcessTemplate failed for SelectionProcessTemplateId {SelectionProcessTemplateId}", SelectionProcessTemplateDTO.SelectionProcessTemplateId); if (autoNumberDTO != null && SelectionProcessTemplateDTO.SelectionProcessTemplateId > 0) { await _AutoNumber.RollbackAutoNumber( "SELECTIONPROCESSTEMPLATE", SelectionProcessTemplateDTO.SelectionProcessTemplateId, LoginDTO).ConfigureAwait(false); } throw; } } #endregion #region Select List public async Task GetSelectListSelectionProcessTemplate(CriteriaDTO criteriaDTO, LoginDTO LoginDTO, CancellationToken ct) { try { return await _SelectionProcessDAL.GetSelectListSelectionProcessTemplate(criteriaDTO, LoginDTO, ct) .ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-selectlist-selectionprocesstemplate-failed", ex); _Logger.LogError(ex, "GetSelectListSelectionProcessTemplate failed"); throw; } } #endregion #region Delete public async Task DeleteSelectionProcessTemplate(int SelectionProcessTemplateId, LoginDTO LoginDTO, CancellationToken ct) { try { GB5Trace.Step("delete-selectionprocesstemplate", new { SelectionProcessTemplateId }); var result = await _SelectionProcessDAL.DeleteSelectionProcessTemplate(SelectionProcessTemplateId, LoginDTO, ct) .ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration( SelectionProcessTemplateId, EntityConstant.OBJECTRECRUITMENTSELECTIONPROCESSTEMPLATE, CacheKeyLevel.CLIENT_LEVEL, LoginDTO); await _KeyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); _Logger.LogInformation("SelectionProcessTemplate {SelectionProcessTemplateId} deleted by user {UserId}", SelectionProcessTemplateId, LoginDTO.UserId); return result; } catch (Exception ex) { GB5Trace.MarkFailed("delete-selectionprocesstemplate-failed", ex); _Logger.LogError(ex, "DeleteSelectionProcessTemplate failed for SelectionProcessTemplateId {SelectionProcessTemplateId}", SelectionProcessTemplateId); throw; } } #endregion #region Get // List variant — returns every stage for a template, ordered by StageOrder. public async Task GetSelectionProcessStage(int SelectionProcessTemplateId, LoginDTO LoginDTO, CancellationToken ct) { try { return await _SelectionProcessDAL.GetSelectionProcessStage(SelectionProcessTemplateId, LoginDTO, ct) .ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-selectionprocessstage-failed", ex); _Logger.LogError(ex, "GetSelectionProcessStage failed for SelectionProcessTemplateId {SelectionProcessTemplateId}", SelectionProcessTemplateId); throw; } } #endregion #region Save public async Task SaveSelectionProcessStage(SelectionProcessStageDTO SelectionProcessStageDTO, LoginDTO LoginDTO, CancellationToken ct) { if (SelectionProcessStageDTO == null) throw new ArgumentNullException(nameof(SelectionProcessStageDTO)); AutoNumberDTO? autoNumberStageDTO = null; try { GB5Trace.Step("validate-selectionprocessstage", new { SelectionProcessStageDTO.SelectionProcessStageId }); await _Validation.NotEmpty( SelectionProcessStageDTO.StageName, nameof(SelectionProcessStageDTO.StageName)).ConfigureAwait(false); bool isNew = SelectionProcessStageDTO.SelectionProcessStageId == 0; SelectionProcessStageDTO.TenantId = LoginDTO.ClientId; SelectionProcessStageDTO.ModifiedById = LoginDTO.UserId; SelectionProcessStageDTO.ModifiedOn = DateTime.UtcNow; if (isNew) { autoNumberStageDTO = await _AutoNumber.GetNumberAsync( 1, "SELECTIONPROCESSSTAGE", LoginDTO).ConfigureAwait(false); SelectionProcessStageDTO.SelectionProcessStageId = autoNumberStageDTO.StartNumber; SelectionProcessStageDTO.CreatedById = LoginDTO.UserId; SelectionProcessStageDTO.CreatedOn = DateTime.UtcNow; if (SelectionProcessStageDTO.Status == 0) SelectionProcessStageDTO.Status = 1; } GB5Trace.Step("save-selectionprocessstage", new { SelectionProcessStageDTO.SelectionProcessStageId, isNew }); await _BaseEntityAppServiceStage.ExecuteSaveAsync( EntityConstant.OBJECTRECRUITMENTSELECTIONPROCESSSTAGE, isNew ? EventTypeConstant.SAVERECRUITMENTSELECTIONPROCESSSTAGEEVENTTYPEID : EventTypeConstant.UPDATERECRUITMENTSELECTIONPROCESSSTAGEEVENTTYPEID, SelectionProcessStageDTO, LoginDTO, async tx => { _ = isNew ? await _SelectionProcessDAL.SaveSelectionProcessStage(SelectionProcessStageDTO, LoginDTO, tx, ct).ConfigureAwait(false) : await _SelectionProcessDAL.UpdateSelectionProcessStage(SelectionProcessStageDTO, LoginDTO, tx, ct).ConfigureAwait(false); return SelectionProcessStageDTO.SelectionProcessStageId; }, null, -1, -1, null, isNew).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeId = isNew ? EventTypeConstant.SAVERECRUITMENTSELECTIONPROCESSSTAGEEVENTTYPEID : EventTypeConstant.UPDATERECRUITMENTSELECTIONPROCESSSTAGEEVENTTYPEID }); var cacheKey = new CacheKeyGeneration().KeyGeneration( SelectionProcessStageDTO.SelectionProcessStageId, EntityConstant.OBJECTRECRUITMENTSELECTIONPROCESSSTAGE, CacheKeyLevel.CLIENT_LEVEL, LoginDTO); await _KeyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); _Logger.LogInformation( "SelectionProcessStage {SelectionProcessStageId} {Action} by user {UserId}", SelectionProcessStageDTO.SelectionProcessStageId, isNew ? "saved" : "updated", LoginDTO.UserId); return isNew ? $"{SuccessResponse.SaveSuccessMessage} {SelectionProcessStageDTO.SelectionProcessStageId}" : $"{SuccessResponse.UpdateSuccessMessage} {SelectionProcessStageDTO.SelectionProcessStageId}"; } catch (ValidationException vex) { GB5Trace.MarkFailed("save-selectionprocessstage-failed", vex); if (autoNumberStageDTO != null && SelectionProcessStageDTO.SelectionProcessStageId > 0) await _AutoNumber.RollbackAutoNumber("SELECTIONPROCESSSTAGE", SelectionProcessStageDTO.SelectionProcessStageId, LoginDTO).ConfigureAwait(false); throw new Exception(vex.Message); } catch (Exception ex) { GB5Trace.MarkFailed("save-selectionprocessstage-failed", ex); _Logger.LogError(ex, "SaveSelectionProcessStage failed for SelectionProcessStageId {SelectionProcessStageId}", SelectionProcessStageDTO.SelectionProcessStageId); if (autoNumberStageDTO != null && SelectionProcessStageDTO.SelectionProcessStageId > 0) { await _AutoNumber.RollbackAutoNumber( "SELECTIONPROCESSSTAGE", SelectionProcessStageDTO.SelectionProcessStageId, LoginDTO).ConfigureAwait(false); } throw; } } #endregion #region Select List public async Task GetSelectListSelectionProcessStage(CriteriaDTO criteriaDTO, LoginDTO LoginDTO, CancellationToken ct) { try { return await _SelectionProcessDAL.GetSelectListSelectionProcessStage(criteriaDTO, LoginDTO, ct) .ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-selectlist-selectionprocessstage-failed", ex); _Logger.LogError(ex, "GetSelectListSelectionProcessStage failed"); throw; } } #endregion #region Delete public async Task DeleteSelectionProcessStage(int SelectionProcessStageId, LoginDTO LoginDTO, CancellationToken ct) { try { GB5Trace.Step("delete-selectionprocessstage", new { SelectionProcessStageId }); var result = await _SelectionProcessDAL.DeleteSelectionProcessStage(SelectionProcessStageId, LoginDTO, ct) .ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration( SelectionProcessStageId, EntityConstant.OBJECTRECRUITMENTSELECTIONPROCESSSTAGE, CacheKeyLevel.CLIENT_LEVEL, LoginDTO); await _KeyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); _Logger.LogInformation("SelectionProcessStage {SelectionProcessStageId} deleted by user {UserId}", SelectionProcessStageId, LoginDTO.UserId); return result; } catch (Exception ex) { GB5Trace.MarkFailed("delete-selectionprocessstage-failed", ex); _Logger.LogError(ex, "DeleteSelectionProcessStage failed for SelectionProcessStageId {SelectionProcessStageId}", SelectionProcessStageId); throw; } } #endregion #region Get public async Task GetSelectionProcessStageQuizId(int SelectionProcessStageId, LoginDTO LoginDTO, CancellationToken ct) { try { return await _SelectionProcessDAL.GetSelectionProcessStageQuizId(SelectionProcessStageId, LoginDTO, ct) .ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-selectionprocessstage-quizid-failed", ex); _Logger.LogError(ex, "GetSelectionProcessStageQuizId failed for SelectionProcessStageId {SelectionProcessStageId}", SelectionProcessStageId); throw; } } public async Task IsSelectionProcessStageTerminalHireCategory(int SelectionProcessStageId, LoginDTO LoginDTO, CancellationToken ct) { try { return await _SelectionProcessDAL.IsSelectionProcessStageTerminalHireCategory(SelectionProcessStageId, LoginDTO, ct) .ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("is-selectionprocessstage-terminalhire-failed", ex); _Logger.LogError(ex, "IsSelectionProcessStageTerminalHireCategory failed for SelectionProcessStageId {SelectionProcessStageId}", SelectionProcessStageId); throw; } } #endregion } }