using System; using System.Collections.Generic; using System.Linq; namespace GB5Shared.DTO.WorkFlow { // ── Workflow Definition ─────────────────────────────────────────────────── /// /// In-memory representation of a full workflow definition loaded from /// MWORKFLOW + MWORKFLOWDETAIL + MWORKFLOWASSIGNMENT. /// public class WorkflowDefinition { public int WorkflowId { get; set; } public string WorkflowName { get; set; } = string.Empty; public int EntityId { get; set; } public string? Particulars { get; set; } public int TenantId { get; set; } public int SortOrder { get; set; } public int Version { get; set; } public int Status { get; set; } public int SourceType { get; set; } public int CreatedById { get; set; } public DateTime CreatedOn { get; set; } public int? ModifiedById { get; set; } public DateTime? ModifiedOn { get; set; } public List Steps { get; set; } = new(); // ── Helpers ────────────────────────────────────────────────────────── /// /// Returns distinct approval levels present in the definition, sorted ascending. /// public List GetApprovalLevels() => Steps.Select(s => s.ApprovalLevel) .Distinct() .OrderBy(l => l) .ToList(); /// /// Returns the next approval level after , /// or null when is the last level. /// public int? GetNextApprovalLevel(int currentLevel) { var levels = GetApprovalLevels(); int idx = levels.IndexOf(currentLevel); if (idx < 0 || idx + 1 >= levels.Count) return null; return levels[idx + 1]; } /// Returns all steps at the given approval level, ordered by SLNO. public IReadOnlyList GetStepsAtLevel(int level) => Steps.Where(s => s.ApprovalLevel == level) .OrderBy(s => s.SlNo) .ToList(); /// Lowest approval level (entry point of the workflow). public int GetFirstApprovalLevel() => GetApprovalLevels().FirstOrDefault(1); // Keep for backward compat with transition-based paths (not used by new level engine) public WorkflowStep? GetInitialStep() => Steps.FirstOrDefault(s => s.IsInitial) ?? Steps.OrderBy(s => s.SlNo).FirstOrDefault(); } // ── Action enum ─────────────────────────────────────────────────────────── public enum WorkflowAction { Submit = 0, Approve = 1, Reject = 2, Return = 3, // send back to previous level / creator Escalate = 4, Cancel = 5 // superseded by resubmission, or the record was deleted } // ── Workflow Step (MWORKFLOWDETAIL + MWORKFLOWASSIGNMENT) ───────────────── public class WorkflowStep { // ── MWORKFLOWDETAIL columns ────────────────────────────────────────── public int WorkflowDetailId { get; set; } public int WorkflowId { get; set; } /// Sequence number within the workflow (SLNO). public int SlNo { get; set; } /// /// Approval level (APPROVALLEVEL). /// Steps with the same level are processed in parallel before advancing. /// public int ApprovalLevel { get; set; } /// /// Unique key derived from WORKFLOWDETAILID (used in history records). /// public string StepKey { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; /// /// 0 = Human, 1 = System, 2 = Auto, 3 = End, 4 = ParallelGroup. /// public int StepType { get; set; } /// /// DB stores: 0 = IS initial, 1 = NOT initial. /// Mapped so that a positive value in the column means IsInitial=true /// when ISINITIAL column value = 1 (i.e. 1 = yes it IS initial — matches /// the existing data where step 18 is flagged). /// NOTE: For level-based routing, use ApprovalLevel instead. /// public bool IsInitial { get; set; } /// Same note as IsInitial. Use ApprovalLevel for routing. public bool IsFinal { get; set; } /// 0 = User, 1 = Role, 2 = Pool, 3 = Dynamic. Assignment target type. public int AssignmentType { get; set; } /// /// Boolean expression evaluated against Facts to determine whether /// this step is applicable for the current document. /// Example: TaskDetailType == 0 /// Null/empty = always applicable. /// public string? EvalCondition { get; set; } /// FK to MWORKFLOWASSIGNMENT. public int AssignmentId { get; set; } public string? Particulars { get; set; } public string? ParallelGroupKey { get; set; } /// SLA hours; 0 = no SLA. public int SlaHours { get; set; } public int EscalationRuleGroupId { get; set; } public int PickListId { get; set; } public int DisplayLabelId { get; set; } // ── MWORKFLOWASSIGNMENT columns (joined) ───────────────────────────── public int WorkflowAssignmentId { get; set; } public string WorkflowAssignmentName { get; set; } = string.Empty; /// /// 0 = User (RULEEXPRESSION holds UserId as string), /// 1 = UserGroup (RULEEXPRESSION holds UserGroupId as string), /// 2 = EnrichQualifier (RULEEXPRESSION is a field name written by a DB_ENRICH /// qualifier into ctx._bag during EnrichForWorkflow; value is the assignee UserId), /// 3 = DynamicSQL (RULEEXPRESSION is a SQL query returning a UserId), /// 4 = Service (RULEEXPRESSION is a service endpoint / identifier — reserved). /// public byte StrategyType { get; set; } /// /// Content depends on StrategyType: /// - 0 (User) : the UserId as a string, e.g. "42" /// - 1 (UserGroup) : the UserGroupId as a string /// - 2 (EnrichQualifier) : field name returned by DB_ENRICH qualifier, e.g. "ReportingToEmployeeId" /// - 3 (DynamicSQL) : parameterised SQL; parameters are injected from Facts /// - 4 (Service) : endpoint/service identifier (reserved) /// public string? RuleExpression { get; set; } public string? AssignmentDescription { get; set; } public int AssignmentTenantId { get; set; } // ── Backward compat (was StrategyTypeId in old engine) ─────────────── /// /// For StrategyType 0/1: direct numeric id parsed from RuleExpression. /// Populated at load time in GetActiveDefinitionAsync. /// public int StrategyTypeId { get; set; } /// Alias kept for backward compatibility. public string? AssignmentValue { get; set; } } // ── Rule groups (used by old activation-rule path) ──────────────────────── public class WorkflowRuleGroup { public long RuleGroupId { get; set; } public string Name { get; set; } = string.Empty; public string Operator { get; set; } = "AND"; public string? Description { get; set; } public IList Rules { get; set; } = new List(); } public class WorkflowRule { public long RuleId { get; set; } public long RuleGroupId { get; set; } public string FieldPath { get; set; } = string.Empty; public string Operator { get; set; } = string.Empty; public string Value { get; set; } = string.Empty; public string ValueType { get; set; } = "String"; } // ── Runtime instances & tasks ───────────────────────────────────────────── public class WorkflowInstance { public int WorkflowInstanceId { get; set; } public int TenantId { get; set; } public int EntityId { get; set; } public int ObjectId { get; set; } public int OUId { get; set; } public int BizTransactionTypeId { get; set; } public int WorkflowId { get; set; } public object? DataJson { get; set; } /// /// JSON-serialized scalar facts from WorkflowStartRequest.Facts (enriched qualifier values). /// Stored at workflow start so EnrichQualifier (StrategyType=2) assignments are available /// at Level 2, 3, and every subsequent level — not just Level 1. /// Merged at lower priority than DataJson; DataJson DTO fields win on key collision. /// public string? FactsJson { get; set; } public long CurrentStepId { get; set; } /// /// Current approval level being processed (1-based). /// Persisted in TWORKFLOWINSTANCE.CURRENTAPPROVALLEVEL. /// public int CurrentApprovalLevel { get; set; } = 1; /// /// 0 = Pending, 1 = Completed, 2 = Rejected, 3 = Returned. /// public int WorkflowStatus { get; set; } public int SortOrder { get; set; } public int Status { get; set; } public int Version { get; set; } public int SourceType { get; set; } public int CreatedById { get; set; } public DateTime CreatedOn { get; set; } public int ModifiedById { get; set; } public DateTime ModifiedOn { get; set; } } public class WorkflowTask { public int WorkflowTaskId { get; set; } public int WorkflowInstanceId { get; set; } public int StepId { get; set; } public int WorkflowTaskStatus { get; set; } public int AssignedToUserId { get; set; } public int AssignedRoleId { get; set; } public int AssignedUserGroupId { get; set; } public DateTime? DueOn { get; set; } public DateTime? CompletedOn { get; set; } public int? ActionTaken { get; set; } public string? Comment { get; set; } public long TenantId { get; set; } public int SortOrder { get; set; } public int Status { get; set; } public int Version { get; set; } public int SourceType { get; set; } public long CreatedById { get; set; } public DateTime CreatedOn { get; set; } public long ModifiedById { get; set; } public DateTime ModifiedOn { get; set; } } public enum WorkflowTaskStatus { Pending = 0, Approved = 1, Rejected = 2, Completed = 3, Cancelled = 4 } public class WorkflowHistory { public int HistoryId { get; set; } public int InstanceId { get; set; } public int ObjectId { get; set; } public object? DataJson { get; set; } public int WorkflowId { get; set; } public int OUID { get; set; } public int BiztransactionTypeId { get; set; } = -1; public string EntityName { get; set; } = string.Empty; public int EntityId { get; set; } public string? StepKey { get; set; } public int ApprovalLevel { get; set; } public int Action { get; set; } public int? ActionByUserId { get; set; } public string? Comment { get; set; } public DateTime ActionOn { get; set; } } public class UserDelegation { public long DelegationId { get; set; } public long PrincipalUserId { get; set; } public long DelegateUserId { get; set; } public DateTime StartsOn { get; set; } public DateTime EndsOn { get; set; } } public class UserPoolMember { public long PoolMemberId { get; set; } public string PoolName { get; set; } = string.Empty; public long UserId { get; set; } } public enum WorkflowInstanceStatus { Pending = 0, Completed = 1, Rejected = 2, Returned = 3, Cancelled = 4 } }