namespace CRMSalesDAL.DTO.Deal; /// /// SalesMind AI "Pipeline & Lead Intelligence" slice — the pipeline entity (TDEAL). Every Deal /// originates from a Marketing TLEAD row via (not optional — this is /// the concrete Marketing→Sales handoff point described in the plan /// (~/.claude/plans/in-entitlement-also-we-async-charm.md, "Marketing→SalesMind SQL handoff")). /// public class DealDTO { #region Deal public int DealId { get; set; } public string DealCode { get; set; } = string.Empty; public string DealName { get; set; } = string.Empty; /// FK to TLEAD — required on every Deal, never a sentinel/optional value. public int LeadId { get; set; } public string? LeadCode { get; set; } public string? LeadName { get; set; } /// 1=Lead, 2=Discovery, 3=Proposal, 4=Negotiation, 5=ClosedWon, 6=ClosedLost — see CK_TDEAL_STAGE. public byte Stage { get; set; } public decimal DealValue { get; set; } /// /// 1=Hot, 2=Warm, 3=Cold — DERIVED, not user-editable. Recomputed in DealBLL.ComputeTemperature /// from // on every save: /// all 3 = "Yes" -> Hot; exactly 2 = "Yes" -> Warm; 0 or 1 = "Yes" -> Cold. Stored so /// reads never recompute it (same precedent as ICPBLL.ComputeABCDCategory / ProductBLL's /// ComputeProductLabel). /// public byte Temperature { get; set; } /// MAN qualification — Money. 1=Yes, 2=Partial, 3=No. public byte MANMoney { get; set; } /// MAN qualification — Authority. 1=Yes, 2=Partial, 3=No. public byte MANAuthority { get; set; } /// MAN qualification — Need. 1=Yes, 2=Partial, 3=No. public byte MANNeed { get; set; } /// /// Updated by DealBLL whenever differs from the previously-persisted value. /// Never set directly by the caller on Update — DealBLL loads the current row and compares. /// public DateTime StageChangedOn { get; set; } /// /// Read-only, computed at query time as DATEDIFF(day, StageChangedOn, GETUTCDATE()) in /// DealQB.GET_DEAL — never persisted, so it can never go stale. 0 on an unsaved/new DTO. /// public int DaysInStage { get; set; } public string? NextAction { get; set; } /// /// Free-text/JSON array of flag strings, e.g. ["No response in 7 days"]. No separate /// RiskFlag master table for v1 — see this module's migration header for the rationale. /// public string? RiskFlags { get; set; } /// /// FK to PayRoll's MEMPLOYEE (cross-module-readable, same pattern Marketing already uses for /// MCONTACT). NULLABLE — not the repo's usual "-1 sentinel + dummy row" convention, because /// MEMPLOYEE carries numerous NOT NULL FK dependencies (WorkOUId, DepartmentId, DesignationId, /// etc.) that make a physical "-1 = not applicable" dummy employee row impractical to seed /// safely. Same reasoning/precedent as ContentRefDTO.SourceContentId's nullable-FK decision. /// public int? RepId { get; set; } public string? RepCode { get; set; } public string? RepName { get; set; } public string? Remarks { get; set; } #endregion #region Base public int CreatedById { get; set; } public DateTime CreatedOn { get; set; } public string? CreatedByName { get; set; } public int ModifiedById { get; set; } public DateTime ModifiedOn { get; set; } public string? ModifiedByName { get; set; } #endregion #region Standard public short SortOrder { get; set; } public byte Status { get; set; } public short Version { get; set; } public int TenantId { get; set; } #endregion }