using System; namespace RecruitmentDAL.DTO.Reports { // Phase 6 analytics (see /Users/venkatv/.claude/plans/can-you-check-the-precious-sunbeam.md, // Phase 6: "extend Phase 1's multi-channel publish ... with cost/performance-per-channel // reporting, feeding Phase 5's source-quality analytics") — job-ad spend performance report. // // Grain: one row per (JobRequisitionId, JobBoardName, ChannelType, CurrencyCode) — i.e. one // row per distinct board/channel spend line on a requisition. Deliberately a NEW, separate // report from CandidateSourceQualityDTO, NOT an extension of it — CandidateSourceQualityQB's // grain is a whole-tenant GROUP BY Candidate.Source only (at most 6 rows per tenant, no // JobRequisitionId dimension at all), so a clean join onto TJOBADSPEND (whose natural grain is // per JobRequisition x JobBoardName) is not available without collapsing away the dimension // that makes spend tracking useful — see JobAdSpendPerformanceQB's doc comment for the full // rationale. ChannelType still mirrors MCANDIDATE.SOURCE / TAPPLICATION.APPLICATIONSOURCE's // 1-6 enum so ApplicationCount/HiredCount below can be computed by joining TAPPLICATION on // (JobRequisitionId, ApplicationSource = ChannelType) — this IS the "feeding Phase 5's // source-quality analytics" the plan calls for, just via a channel-typed join rather than a // shared query surface. public class JobAdSpendPerformanceDTO { public int JobRequisitionId { get; set; } public string? RequisitionCode { get; set; } // 1=Website 2=JobPortal 3=Agency 4=Referral 5=Internal 6=Direct/Manual public byte ChannelType { get; set; } public string? ChannelName { get; set; } public string? JobBoardName { get; set; } public string? CurrencyCode { get; set; } public decimal TotalSpend { get; set; } // Distinct TAPPLICATION rows for this requisition whose ApplicationSource matches this // row's ChannelType (not scoped to this specific JobBoardName — TAPPLICATION has no // board-level attribution, only the coarser ChannelType/ApplicationSource). public int ApplicationCount { get; set; } // Same "genuine Hired" structural signal as CandidateSourceQualityDTO.HiredCount / // ApplicationCycleTimeDTO.IsHired / CandidateConversionBLL. public int HiredCount { get; set; } // TotalSpend / ApplicationCount, 0 when ApplicationCount = 0. public decimal CostPerApplication { get; set; } // TotalSpend / HiredCount, 0 when HiredCount = 0. public decimal CostPerHire { get; set; } } }