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
}
}