using System; namespace RecruitmentDAL.DTO.Reports { // Phase 5 analytics (see /Users/venkatv/.claude/plans/can-you-check-the-precious-sunbeam.md) — // cycle-time report. Grain: one row per (Application, SelectionProcessStage) — i.e. one row // per TAPPLICATIONSTAGEHISTORY entry — NOT one row per Application/JobRequisition. This is // deliberate: TAPPLICATIONSTAGEHISTORY.StageEnteredOn/StageExitedOn are per-Application-per- // stage, so per-stage duration can only be computed at this grain. A JobRequisition-level // rollup (avg time-to-fill per requisition, avg time-in-stage per stage) is a client-side/SQL // GROUP BY over these rows — TimeToFillDays is already repeated identically across every stage // row of the same Application so a simple GROUP BY ApplicationId (or JobRequisitionId) MAX() // reconstructs it without a second query. public class ApplicationCycleTimeDTO { public int ApplicationId { get; set; } public int CandidateId { get; set; } public string? CandidateName { get; set; } public int JobRequisitionId { get; set; } public string? RequisitionCode { get; set; } public int SelectionProcessStageId { get; set; } public string? StageName { get; set; } // Ordering of this stage within its template's pipeline (MSELECTIONPROCESSSTAGE.STAGEORDER) public short StageOrder { get; set; } // 1=Applied 2=Screening 3=Interview 4=Assessment 5=Offer 6=PreBoarding 7=Terminal public byte StageCategory { get; set; } public DateTime StageEnteredOn { get; set; } // NULL = candidate is still in this stage (has not exited it yet) public DateTime? StageExitedOn { get; set; } // DATEDIFF(DAY, StageEnteredOn, ISNULL(StageExitedOn, UTCNOW)) — computed in SQL public int DaysInStage { get; set; } // "Genuine Hired" signal — mirrors CandidateConversionBLL's own structural definition: // Application's CURRENT stage is Terminal (StageCategory=7, IsTerminal=1) AND that stage's // most recent ApplicationStageHistory row has Outcome=Passed(2). Repeated identically on // every stage row belonging to the same Application. public bool IsHired { get; set; } // Total time-to-fill: first Applied-category (StageCategory=1) stage's StageEnteredOn to // the Hired terminal stage's StageEnteredOn. NULL when the Application is not (yet, or // never) Hired. Repeated identically on every stage row belonging to the same Application. public int? TimeToFillDays { get; set; } } }