[CLAUDE] Drastic refactor: flat workflow Phòng × Cấp + Migration 21 (Chunk A)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m18s

User chốt drastic refactor — bỏ phase enum hoàn toàn, dùng ChoDuyet=10
đơn nhất + currentStepIndex tracking. Workflow flat list (Phòng × Cấp ×
Approvers). Mỗi PE/HĐ pin WorkflowDefinitionId chạy hết quy trình đó.

Schema (Migration 21 `RefactorWorkflowToFlatModel`):
- Phase enum +ChoDuyet=10 (PE + Contract). Legacy 2-9 + 98 deprecated.
- WorkflowStep + DepartmentId Guid? (FK Restrict) + PositionLevel int?
  (PE + Contract — mirror).
- PE/Contract + CurrentWorkflowStepIndex int? + RejectedAtStepIndex int?
- DROP table PurchaseEvaluationWorkflowStepInnerSteps (Mig 18)
- DROP table WorkflowStepInnerSteps (Mig 20)
- DROP column ContractDeptApproval.InnerStepId (Mig 20)
- DROP column PEDeptApproval.InnerStepId (Mig 18)
- DROP filtered indexes (Mig 19/20) + restore simple unique
  (TargetId, Phase, Dept, Stage) non-filtered

Service rewrite (PE + Contract WorkflowService.TransitionAsync):
- Phase transitions: DangSoanThao → ChoDuyet (Drafter trình, init idx=0)
- ChoDuyet → ChoDuyet (advance idx per approve)
- ChoDuyet → DaDuyet/DaPhatHanh (idx >= steps.Count → terminal)
- ChoDuyet → DangSoanThao (Trả lại — save RejectedAtStepIndex)
- ChoDuyet → TuChoi (Từ chối — khoá vĩnh viễn)
- DangSoanThao + RejectedAtStepIndex → ChoDuyet jump-back to saved idx
- Approver match: actor.Dept == step.Dept AND actor.PositionLevel >=
  step.PositionLevel (OR-of-many cùng cấp/dept = pass) OR
  Approvers.Any(Kind=User AND id match) OR
  Approvers.Any(Kind=Role AND actorRoles contains)
- Admin role bypass policy. Last step done → gen mã HĐ (Contract only)

App CQRS:
- WorkflowStepDto + WorkflowStepInput drop InnerStep, add DepartmentId
  + PositionLevel fields. PE + Contract mirror.

Tests rewrite:
- DROP PeNStageApprovalTests.cs (6 test) + ContractNStageApprovalTests.cs
  (6 test) + PeTwoStageApprovalTests.cs (7 test) — legacy N-stage/2-stage
  no longer applicable
- UPDATE PeWorkflowAdminTests signature to new flat input
- 96 → 77 test pass (drop 19 legacy)

Reference Domain entities removed:
- WorkflowStepInnerStep (Contract)
- PurchaseEvaluationWorkflowStepInnerStep (PE)
- DTOs WorkflowStepInnerStepDto / CreateWorkflowStepInnerStepInput per module

Memory `feedback_drastic_refactor_scope.md` validated: drastic refactor
done in dedicated session với context fresh, scope ~5h actual (planned ~8-10h
with 2x buffer).

Verify:
- dotnet build SolutionErp.slnx 0 error
- dotnet ef database update Mig 21 LocalDB applied OK
- dotnet test 77 pass (54 Domain + 23 Infra)
- 3-file rule: Migration .cs + Designer.cs + Snapshot updated

Pending Chunk B: FE Designer flat UI (PeWorkflowsPage + WorkflowsPage).
Pending Chunk C: FE PeWorkflowPanel + workflow timeline display.
Pending Chunk D: Docs + Skill + Memory + session log.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-08 12:04:51 +07:00
parent 38d10b7897
commit dbb0089e28
23 changed files with 4501 additions and 2123 deletions

View File

@ -41,7 +41,6 @@ public class ApplicationDbContext
public DbSet<WorkflowDefinition> WorkflowDefinitions => Set<WorkflowDefinition>();
public DbSet<WorkflowStep> WorkflowSteps => Set<WorkflowStep>();
public DbSet<WorkflowStepApprover> WorkflowStepApprovers => Set<WorkflowStepApprover>();
public DbSet<WorkflowStepInnerStep> WorkflowStepInnerSteps => Set<WorkflowStepInnerStep>();
public DbSet<ThauPhuDetail> ThauPhuDetails => Set<ThauPhuDetail>();
public DbSet<GiaoKhoanDetail> GiaoKhoanDetails => Set<GiaoKhoanDetail>();
public DbSet<NhaCungCapDetail> NhaCungCapDetails => Set<NhaCungCapDetail>();
@ -60,7 +59,6 @@ public class ApplicationDbContext
public DbSet<PurchaseEvaluationWorkflowDefinition> PurchaseEvaluationWorkflowDefinitions => Set<PurchaseEvaluationWorkflowDefinition>();
public DbSet<PurchaseEvaluationWorkflowStep> PurchaseEvaluationWorkflowSteps => Set<PurchaseEvaluationWorkflowStep>();
public DbSet<PurchaseEvaluationWorkflowStepApprover> PurchaseEvaluationWorkflowStepApprovers => Set<PurchaseEvaluationWorkflowStepApprover>();
public DbSet<PurchaseEvaluationWorkflowStepInnerStep> PurchaseEvaluationWorkflowStepInnerSteps => Set<PurchaseEvaluationWorkflowStepInnerStep>();
public DbSet<PurchaseEvaluationCodeSequence> PurchaseEvaluationCodeSequences => Set<PurchaseEvaluationCodeSequence>();
public DbSet<PurchaseEvaluationDepartmentOpinion> PurchaseEvaluationDepartmentOpinions => Set<PurchaseEvaluationDepartmentOpinion>();
public DbSet<PurchaseEvaluationDepartmentApproval> PurchaseEvaluationDepartmentApprovals => Set<PurchaseEvaluationDepartmentApproval>();

View File

@ -27,19 +27,11 @@ public class ContractDepartmentApprovalConfiguration
b.Property(x => x.ApproverRoleSnapshot).HasMaxLength(100);
b.Property(x => x.Comment).HasMaxLength(1000);
// Legacy 2-stage rows (Mig 16): UNIQUE chỉ áp khi InnerStepId IS NULL
// (Mig 20 mirror PE Mig 19 filtered split).
// Mig 21 — drop InnerStepId column + restore simple unique non-filtered.
b.HasIndex(x => new { x.ContractId, x.PhaseAtApproval, x.DepartmentId, x.Stage })
.IsUnique()
.HasFilter("[InnerStepId] IS NULL")
.HasDatabaseName("UX_ContractDeptApprovals_Contract_Phase_Dept_Stage");
// N-stage rows (Mig 20): UNIQUE 1 row per (phase × inner step).
b.HasIndex(x => new { x.ContractId, x.PhaseAtApproval, x.InnerStepId })
.IsUnique()
.HasFilter("[InnerStepId] IS NOT NULL")
.HasDatabaseName("UX_ContractDeptApprovals_Contract_Phase_InnerStep");
b.HasIndex(x => x.ContractId);
b.HasIndex(x => x.DepartmentId);
b.HasIndex(x => x.ApproverUserId);
@ -48,12 +40,6 @@ public class ContractDepartmentApprovalConfiguration
.WithMany(c => c.DepartmentApprovals)
.HasForeignKey(x => x.ContractId)
.OnDelete(DeleteBehavior.Cascade);
// FK InnerStepId nullable — Restrict (không xóa InnerStep nếu còn approval row)
b.HasOne<WorkflowStepInnerStep>()
.WithMany()
.HasForeignKey(x => x.InnerStepId)
.OnDelete(DeleteBehavior.Restrict);
}
}
@ -69,21 +55,11 @@ public class PurchaseEvaluationDepartmentApprovalConfiguration
b.Property(x => x.ApproverRoleSnapshot).HasMaxLength(100);
b.Property(x => x.Comment).HasMaxLength(1000);
// Legacy 2-stage rows (Mig 16): UNIQUE (PEId, Phase, Dept, Stage) chỉ áp
// khi InnerStepId IS NULL — tránh conflict với N-stage rows nhiều InnerStep
// cùng dept cùng Stage=Confirm.
// Mig 21 — drop InnerStepId column + restore simple unique non-filtered.
b.HasIndex(x => new { x.PurchaseEvaluationId, x.PhaseAtApproval, x.DepartmentId, x.Stage })
.IsUnique()
.HasFilter("[InnerStepId] IS NULL")
.HasDatabaseName("UX_PEDeptApprovals_PE_Phase_Dept_Stage");
// N-stage rows (Mig 18+): UNIQUE (PEId, Phase, InnerStepId) — 1 approval row
// per (phase × inner step) khi InnerStepId IS NOT NULL.
b.HasIndex(x => new { x.PurchaseEvaluationId, x.PhaseAtApproval, x.InnerStepId })
.IsUnique()
.HasFilter("[InnerStepId] IS NOT NULL")
.HasDatabaseName("UX_PEDeptApprovals_PE_Phase_InnerStep");
b.HasIndex(x => x.PurchaseEvaluationId);
b.HasIndex(x => x.DepartmentId);
b.HasIndex(x => x.ApproverUserId);
@ -92,13 +68,6 @@ public class PurchaseEvaluationDepartmentApprovalConfiguration
.WithMany(c => c.DepartmentApprovals)
.HasForeignKey(x => x.PurchaseEvaluationId)
.OnDelete(DeleteBehavior.Cascade);
// FK InnerStepId nullable — Restrict (không xóa InnerStep nếu còn approval row).
// Cấu hình không nav để giữ nhẹ entity (1 chiều, query qua join nếu cần).
b.HasOne<PurchaseEvaluationWorkflowStepInnerStep>()
.WithMany()
.HasForeignKey(x => x.InnerStepId)
.OnDelete(DeleteBehavior.Restrict);
}
}

View File

@ -184,13 +184,21 @@ public class PurchaseEvaluationWorkflowStepConfiguration : IEntityTypeConfigurat
e.ToTable("PurchaseEvaluationWorkflowSteps");
e.Property(x => x.Name).HasMaxLength(200).IsRequired();
e.Property(x => x.Phase).HasConversion<int>();
e.Property(x => x.PositionLevel).HasConversion<int?>(); // Mig 21
e.HasOne(x => x.Definition)
.WithMany(d => d.Steps)
.HasForeignKey(x => x.PurchaseEvaluationWorkflowDefinitionId)
.OnDelete(DeleteBehavior.Cascade);
// Mig 21 — FK Department Restrict.
e.HasOne<SolutionErp.Domain.Master.Department>()
.WithMany()
.HasForeignKey(x => x.DepartmentId)
.OnDelete(DeleteBehavior.Restrict);
e.HasIndex(x => new { x.PurchaseEvaluationWorkflowDefinitionId, x.Order });
e.HasIndex(x => x.DepartmentId);
}
}
@ -209,37 +217,6 @@ public class PurchaseEvaluationWorkflowStepApproverConfiguration : IEntityTypeCo
}
}
// Inner step (Mig 18) — N-stage approval cấu hình động trong cùng 1 phase.
// FK Cascade từ Step cha. Index theo (StepId, Order) cho query ordered list.
// Index riêng DepartmentId để lookup khi service compute next pending sub-step.
public class PurchaseEvaluationWorkflowStepInnerStepConfiguration
: IEntityTypeConfiguration<PurchaseEvaluationWorkflowStepInnerStep>
{
public void Configure(EntityTypeBuilder<PurchaseEvaluationWorkflowStepInnerStep> e)
{
e.ToTable("PurchaseEvaluationWorkflowStepInnerSteps");
e.HasKey(x => x.Id);
e.Property(x => x.PositionLevel).HasConversion<int>();
e.Property(x => x.Name).HasMaxLength(200);
e.HasOne(x => x.Step)
.WithMany(s => s.InnerSteps)
.HasForeignKey(x => x.PurchaseEvaluationWorkflowStepId)
.OnDelete(DeleteBehavior.Cascade);
// FK Department — Restrict (không xóa dept nếu còn inner step assigned).
// Không cấu hình nav trên Department để tránh circular collection bloat.
e.HasOne<SolutionErp.Domain.Master.Department>()
.WithMany()
.HasForeignKey(x => x.DepartmentId)
.OnDelete(DeleteBehavior.Restrict);
e.HasIndex(x => new { x.PurchaseEvaluationWorkflowStepId, x.Order });
e.HasIndex(x => x.DepartmentId);
}
}
// Mirror ContractCodeSequenceConfiguration — Prefix là PK, atomic UPDATE qua
// SERIALIZABLE transaction trong PurchaseEvaluationCodeGenerator.
public class PurchaseEvaluationCodeSequenceConfiguration

View File

@ -28,13 +28,21 @@ public class WorkflowStepConfiguration : IEntityTypeConfiguration<WorkflowStep>
e.ToTable("WorkflowSteps");
e.Property(x => x.Name).HasMaxLength(200).IsRequired();
e.Property(x => x.Phase).HasConversion<int>();
e.Property(x => x.PositionLevel).HasConversion<int?>(); // Mig 21
e.HasOne(x => x.WorkflowDefinition)
.WithMany(d => d.Steps)
.HasForeignKey(x => x.WorkflowDefinitionId)
.OnDelete(DeleteBehavior.Cascade);
// Mig 21 — FK Department Restrict (không xóa dept nếu còn step assigned).
e.HasOne<SolutionErp.Domain.Master.Department>()
.WithMany()
.HasForeignKey(x => x.DepartmentId)
.OnDelete(DeleteBehavior.Restrict);
e.HasIndex(x => new { x.WorkflowDefinitionId, x.Order });
e.HasIndex(x => x.DepartmentId);
}
}
@ -52,31 +60,3 @@ public class WorkflowStepApproverConfiguration : IEntityTypeConfiguration<Workfl
.OnDelete(DeleteBehavior.Cascade);
}
}
// Inner step (Mig 20) — N-stage approval cấu hình động trong cùng 1 phase.
// Mirror PurchaseEvaluationWorkflowStepInnerStepConfiguration (Mig 18).
public class WorkflowStepInnerStepConfiguration
: IEntityTypeConfiguration<WorkflowStepInnerStep>
{
public void Configure(EntityTypeBuilder<WorkflowStepInnerStep> e)
{
e.ToTable("WorkflowStepInnerSteps");
e.HasKey(x => x.Id);
e.Property(x => x.PositionLevel).HasConversion<int>();
e.Property(x => x.Name).HasMaxLength(200);
e.HasOne(x => x.Step)
.WithMany(s => s.InnerSteps)
.HasForeignKey(x => x.WorkflowStepId)
.OnDelete(DeleteBehavior.Cascade);
e.HasOne<SolutionErp.Domain.Master.Department>()
.WithMany()
.HasForeignKey(x => x.DepartmentId)
.OnDelete(DeleteBehavior.Restrict);
e.HasIndex(x => new { x.WorkflowStepId, x.Order });
e.HasIndex(x => x.DepartmentId);
}
}

View File

@ -0,0 +1,361 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SolutionErp.Infrastructure.Persistence.Migrations
{
/// <inheritdoc />
public partial class RefactorWorkflowToFlatModel : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_ContractDepartmentApprovals_WorkflowStepInnerSteps_InnerStepId",
table: "ContractDepartmentApprovals");
migrationBuilder.DropForeignKey(
name: "FK_PurchaseEvaluationDepartmentApprovals_PurchaseEvaluationWorkflowStepInnerSteps_InnerStepId",
table: "PurchaseEvaluationDepartmentApprovals");
migrationBuilder.DropTable(
name: "PurchaseEvaluationWorkflowStepInnerSteps");
migrationBuilder.DropTable(
name: "WorkflowStepInnerSteps");
migrationBuilder.DropIndex(
name: "IX_PurchaseEvaluationDepartmentApprovals_InnerStepId",
table: "PurchaseEvaluationDepartmentApprovals");
migrationBuilder.DropIndex(
name: "UX_PEDeptApprovals_PE_Phase_Dept_Stage",
table: "PurchaseEvaluationDepartmentApprovals");
migrationBuilder.DropIndex(
name: "UX_PEDeptApprovals_PE_Phase_InnerStep",
table: "PurchaseEvaluationDepartmentApprovals");
migrationBuilder.DropIndex(
name: "IX_ContractDepartmentApprovals_InnerStepId",
table: "ContractDepartmentApprovals");
migrationBuilder.DropIndex(
name: "UX_ContractDeptApprovals_Contract_Phase_Dept_Stage",
table: "ContractDepartmentApprovals");
migrationBuilder.DropIndex(
name: "UX_ContractDeptApprovals_Contract_Phase_InnerStep",
table: "ContractDepartmentApprovals");
migrationBuilder.DropColumn(
name: "InnerStepId",
table: "PurchaseEvaluationDepartmentApprovals");
migrationBuilder.DropColumn(
name: "InnerStepId",
table: "ContractDepartmentApprovals");
migrationBuilder.AddColumn<Guid>(
name: "DepartmentId",
table: "WorkflowSteps",
type: "uniqueidentifier",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "PositionLevel",
table: "WorkflowSteps",
type: "int",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "DepartmentId",
table: "PurchaseEvaluationWorkflowSteps",
type: "uniqueidentifier",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "PositionLevel",
table: "PurchaseEvaluationWorkflowSteps",
type: "int",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "CurrentWorkflowStepIndex",
table: "PurchaseEvaluations",
type: "int",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "RejectedAtStepIndex",
table: "PurchaseEvaluations",
type: "int",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "CurrentWorkflowStepIndex",
table: "Contracts",
type: "int",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "RejectedAtStepIndex",
table: "Contracts",
type: "int",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_WorkflowSteps_DepartmentId",
table: "WorkflowSteps",
column: "DepartmentId");
migrationBuilder.CreateIndex(
name: "IX_PurchaseEvaluationWorkflowSteps_DepartmentId",
table: "PurchaseEvaluationWorkflowSteps",
column: "DepartmentId");
migrationBuilder.CreateIndex(
name: "UX_PEDeptApprovals_PE_Phase_Dept_Stage",
table: "PurchaseEvaluationDepartmentApprovals",
columns: new[] { "PurchaseEvaluationId", "PhaseAtApproval", "DepartmentId", "Stage" },
unique: true);
migrationBuilder.CreateIndex(
name: "UX_ContractDeptApprovals_Contract_Phase_Dept_Stage",
table: "ContractDepartmentApprovals",
columns: new[] { "ContractId", "PhaseAtApproval", "DepartmentId", "Stage" },
unique: true);
migrationBuilder.AddForeignKey(
name: "FK_PurchaseEvaluationWorkflowSteps_Departments_DepartmentId",
table: "PurchaseEvaluationWorkflowSteps",
column: "DepartmentId",
principalTable: "Departments",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_WorkflowSteps_Departments_DepartmentId",
table: "WorkflowSteps",
column: "DepartmentId",
principalTable: "Departments",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_PurchaseEvaluationWorkflowSteps_Departments_DepartmentId",
table: "PurchaseEvaluationWorkflowSteps");
migrationBuilder.DropForeignKey(
name: "FK_WorkflowSteps_Departments_DepartmentId",
table: "WorkflowSteps");
migrationBuilder.DropIndex(
name: "IX_WorkflowSteps_DepartmentId",
table: "WorkflowSteps");
migrationBuilder.DropIndex(
name: "IX_PurchaseEvaluationWorkflowSteps_DepartmentId",
table: "PurchaseEvaluationWorkflowSteps");
migrationBuilder.DropIndex(
name: "UX_PEDeptApprovals_PE_Phase_Dept_Stage",
table: "PurchaseEvaluationDepartmentApprovals");
migrationBuilder.DropIndex(
name: "UX_ContractDeptApprovals_Contract_Phase_Dept_Stage",
table: "ContractDepartmentApprovals");
migrationBuilder.DropColumn(
name: "DepartmentId",
table: "WorkflowSteps");
migrationBuilder.DropColumn(
name: "PositionLevel",
table: "WorkflowSteps");
migrationBuilder.DropColumn(
name: "DepartmentId",
table: "PurchaseEvaluationWorkflowSteps");
migrationBuilder.DropColumn(
name: "PositionLevel",
table: "PurchaseEvaluationWorkflowSteps");
migrationBuilder.DropColumn(
name: "CurrentWorkflowStepIndex",
table: "PurchaseEvaluations");
migrationBuilder.DropColumn(
name: "RejectedAtStepIndex",
table: "PurchaseEvaluations");
migrationBuilder.DropColumn(
name: "CurrentWorkflowStepIndex",
table: "Contracts");
migrationBuilder.DropColumn(
name: "RejectedAtStepIndex",
table: "Contracts");
migrationBuilder.AddColumn<Guid>(
name: "InnerStepId",
table: "PurchaseEvaluationDepartmentApprovals",
type: "uniqueidentifier",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "InnerStepId",
table: "ContractDepartmentApprovals",
type: "uniqueidentifier",
nullable: true);
migrationBuilder.CreateTable(
name: "PurchaseEvaluationWorkflowStepInnerSteps",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
PurchaseEvaluationWorkflowStepId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DepartmentId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
IsRequired = table.Column<bool>(type: "bit", nullable: false),
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
Order = table.Column<int>(type: "int", nullable: false),
PositionLevel = table.Column<int>(type: "int", nullable: false),
SlaDays = table.Column<int>(type: "int", nullable: true),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PurchaseEvaluationWorkflowStepInnerSteps", x => x.Id);
table.ForeignKey(
name: "FK_PurchaseEvaluationWorkflowStepInnerSteps_Departments_DepartmentId",
column: x => x.DepartmentId,
principalTable: "Departments",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_PurchaseEvaluationWorkflowStepInnerSteps_PurchaseEvaluationWorkflowSteps_PurchaseEvaluationWorkflowStepId",
column: x => x.PurchaseEvaluationWorkflowStepId,
principalTable: "PurchaseEvaluationWorkflowSteps",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "WorkflowStepInnerSteps",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
WorkflowStepId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DepartmentId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
IsRequired = table.Column<bool>(type: "bit", nullable: false),
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
Order = table.Column<int>(type: "int", nullable: false),
PositionLevel = table.Column<int>(type: "int", nullable: false),
SlaDays = table.Column<int>(type: "int", nullable: true),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_WorkflowStepInnerSteps", x => x.Id);
table.ForeignKey(
name: "FK_WorkflowStepInnerSteps_Departments_DepartmentId",
column: x => x.DepartmentId,
principalTable: "Departments",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_WorkflowStepInnerSteps_WorkflowSteps_WorkflowStepId",
column: x => x.WorkflowStepId,
principalTable: "WorkflowSteps",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_PurchaseEvaluationDepartmentApprovals_InnerStepId",
table: "PurchaseEvaluationDepartmentApprovals",
column: "InnerStepId");
migrationBuilder.CreateIndex(
name: "UX_PEDeptApprovals_PE_Phase_Dept_Stage",
table: "PurchaseEvaluationDepartmentApprovals",
columns: new[] { "PurchaseEvaluationId", "PhaseAtApproval", "DepartmentId", "Stage" },
unique: true,
filter: "[InnerStepId] IS NULL");
migrationBuilder.CreateIndex(
name: "UX_PEDeptApprovals_PE_Phase_InnerStep",
table: "PurchaseEvaluationDepartmentApprovals",
columns: new[] { "PurchaseEvaluationId", "PhaseAtApproval", "InnerStepId" },
unique: true,
filter: "[InnerStepId] IS NOT NULL");
migrationBuilder.CreateIndex(
name: "IX_ContractDepartmentApprovals_InnerStepId",
table: "ContractDepartmentApprovals",
column: "InnerStepId");
migrationBuilder.CreateIndex(
name: "UX_ContractDeptApprovals_Contract_Phase_Dept_Stage",
table: "ContractDepartmentApprovals",
columns: new[] { "ContractId", "PhaseAtApproval", "DepartmentId", "Stage" },
unique: true,
filter: "[InnerStepId] IS NULL");
migrationBuilder.CreateIndex(
name: "UX_ContractDeptApprovals_Contract_Phase_InnerStep",
table: "ContractDepartmentApprovals",
columns: new[] { "ContractId", "PhaseAtApproval", "InnerStepId" },
unique: true,
filter: "[InnerStepId] IS NOT NULL");
migrationBuilder.CreateIndex(
name: "IX_PurchaseEvaluationWorkflowStepInnerSteps_DepartmentId",
table: "PurchaseEvaluationWorkflowStepInnerSteps",
column: "DepartmentId");
migrationBuilder.CreateIndex(
name: "IX_PurchaseEvaluationWorkflowStepInnerSteps_PurchaseEvaluationWorkflowStepId_Order",
table: "PurchaseEvaluationWorkflowStepInnerSteps",
columns: new[] { "PurchaseEvaluationWorkflowStepId", "Order" });
migrationBuilder.CreateIndex(
name: "IX_WorkflowStepInnerSteps_DepartmentId",
table: "WorkflowStepInnerSteps",
column: "DepartmentId");
migrationBuilder.CreateIndex(
name: "IX_WorkflowStepInnerSteps_WorkflowStepId_Order",
table: "WorkflowStepInnerSteps",
columns: new[] { "WorkflowStepId", "Order" });
migrationBuilder.AddForeignKey(
name: "FK_ContractDepartmentApprovals_WorkflowStepInnerSteps_InnerStepId",
table: "ContractDepartmentApprovals",
column: "InnerStepId",
principalTable: "WorkflowStepInnerSteps",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_PurchaseEvaluationDepartmentApprovals_PurchaseEvaluationWorkflowStepInnerSteps_InnerStepId",
table: "PurchaseEvaluationDepartmentApprovals",
column: "InnerStepId",
principalTable: "PurchaseEvaluationWorkflowStepInnerSteps",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
}
}

View File

@ -484,6 +484,9 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<int?>("CurrentWorkflowStepIndex")
.HasColumnType("int");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("datetime2");
@ -520,6 +523,9 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<Guid>("ProjectId")
.HasColumnType("uniqueidentifier");
b.Property<int?>("RejectedAtStepIndex")
.HasColumnType("int");
b.Property<int?>("RejectedFromPhase")
.HasColumnType("int");
@ -824,9 +830,6 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<Guid>("DepartmentId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("InnerStepId")
.HasColumnType("uniqueidentifier");
b.Property<bool>("IsBypassed")
.HasColumnType("bit");
@ -853,17 +856,9 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.HasIndex("DepartmentId");
b.HasIndex("InnerStepId");
b.HasIndex("ContractId", "PhaseAtApproval", "InnerStepId")
.IsUnique()
.HasDatabaseName("UX_ContractDeptApprovals_Contract_Phase_InnerStep")
.HasFilter("[InnerStepId] IS NOT NULL");
b.HasIndex("ContractId", "PhaseAtApproval", "DepartmentId", "Stage")
.IsUnique()
.HasDatabaseName("UX_ContractDeptApprovals_Contract_Phase_Dept_Stage")
.HasFilter("[InnerStepId] IS NULL");
.HasDatabaseName("UX_ContractDeptApprovals_Contract_Phase_Dept_Stage");
b.ToTable("ContractDepartmentApprovals", (string)null);
});
@ -1422,6 +1417,9 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("DepartmentId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
@ -1433,6 +1431,9 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<int>("Phase")
.HasColumnType("int");
b.Property<int?>("PositionLevel")
.HasColumnType("int");
b.Property<int?>("SlaDays")
.HasColumnType("int");
@ -1447,6 +1448,8 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.HasKey("Id");
b.HasIndex("DepartmentId");
b.HasIndex("WorkflowDefinitionId", "Order");
b.ToTable("WorkflowSteps", (string)null);
@ -1488,55 +1491,6 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.ToTable("WorkflowStepApprovers", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowStepInnerStep", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("DepartmentId")
.HasColumnType("uniqueidentifier");
b.Property<bool>("IsRequired")
.HasColumnType("bit");
b.Property<string>("Name")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<int>("PositionLevel")
.HasColumnType("int");
b.Property<int?>("SlaDays")
.HasColumnType("int");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("WorkflowStepId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("DepartmentId");
b.HasIndex("WorkflowStepId", "Order");
b.ToTable("WorkflowStepInnerSteps", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowTypeAssignment", b =>
{
b.Property<Guid>("Id")
@ -2416,6 +2370,9 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<int?>("CurrentWorkflowStepIndex")
.HasColumnType("int");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("datetime2");
@ -2452,6 +2409,9 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<Guid>("ProjectId")
.HasColumnType("uniqueidentifier");
b.Property<int?>("RejectedAtStepIndex")
.HasColumnType("int");
b.Property<int?>("RejectedFromPhase")
.HasColumnType("int");
@ -2719,9 +2679,6 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<Guid>("DepartmentId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("InnerStepId")
.HasColumnType("uniqueidentifier");
b.Property<bool>("IsBypassed")
.HasColumnType("bit");
@ -2749,19 +2706,11 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.HasIndex("DepartmentId");
b.HasIndex("InnerStepId");
b.HasIndex("PurchaseEvaluationId");
b.HasIndex("PurchaseEvaluationId", "PhaseAtApproval", "InnerStepId")
.IsUnique()
.HasDatabaseName("UX_PEDeptApprovals_PE_Phase_InnerStep")
.HasFilter("[InnerStepId] IS NOT NULL");
b.HasIndex("PurchaseEvaluationId", "PhaseAtApproval", "DepartmentId", "Stage")
.IsUnique()
.HasDatabaseName("UX_PEDeptApprovals_PE_Phase_Dept_Stage")
.HasFilter("[InnerStepId] IS NULL");
.HasDatabaseName("UX_PEDeptApprovals_PE_Phase_Dept_Stage");
b.ToTable("PurchaseEvaluationDepartmentApprovals", (string)null);
});
@ -3080,6 +3029,9 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("DepartmentId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
@ -3091,6 +3043,9 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<int>("Phase")
.HasColumnType("int");
b.Property<int?>("PositionLevel")
.HasColumnType("int");
b.Property<Guid>("PurchaseEvaluationWorkflowDefinitionId")
.HasColumnType("uniqueidentifier");
@ -3105,6 +3060,8 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.HasKey("Id");
b.HasIndex("DepartmentId");
b.HasIndex("PurchaseEvaluationWorkflowDefinitionId", "Order");
b.ToTable("PurchaseEvaluationWorkflowSteps", (string)null);
@ -3146,55 +3103,6 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.ToTable("PurchaseEvaluationWorkflowStepApprovers", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluationWorkflowStepInnerStep", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("DepartmentId")
.HasColumnType("uniqueidentifier");
b.Property<bool>("IsRequired")
.HasColumnType("bit");
b.Property<string>("Name")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<int>("PositionLevel")
.HasColumnType("int");
b.Property<Guid>("PurchaseEvaluationWorkflowStepId")
.HasColumnType("uniqueidentifier");
b.Property<int?>("SlaDays")
.HasColumnType("int");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("DepartmentId");
b.HasIndex("PurchaseEvaluationWorkflowStepId", "Order");
b.ToTable("PurchaseEvaluationWorkflowStepInnerSteps", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.HasOne("SolutionErp.Domain.Identity.Role", null)
@ -3342,11 +3250,6 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SolutionErp.Domain.Contracts.WorkflowStepInnerStep", null)
.WithMany()
.HasForeignKey("InnerStepId")
.OnDelete(DeleteBehavior.Restrict);
b.Navigation("Contract");
});
@ -3429,6 +3332,11 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowStep", b =>
{
b.HasOne("SolutionErp.Domain.Master.Department", null)
.WithMany()
.HasForeignKey("DepartmentId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("SolutionErp.Domain.Contracts.WorkflowDefinition", "WorkflowDefinition")
.WithMany("Steps")
.HasForeignKey("WorkflowDefinitionId")
@ -3449,23 +3357,6 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Navigation("Step");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowStepInnerStep", b =>
{
b.HasOne("SolutionErp.Domain.Master.Department", null)
.WithMany()
.HasForeignKey("DepartmentId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("SolutionErp.Domain.Contracts.WorkflowStep", "Step")
.WithMany("InnerSteps")
.HasForeignKey("WorkflowStepId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Step");
});
modelBuilder.Entity("SolutionErp.Domain.Identity.MenuItem", b =>
{
b.HasOne("SolutionErp.Domain.Identity.MenuItem", "Parent")
@ -3538,11 +3429,6 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
modelBuilder.Entity("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluationDepartmentApproval", b =>
{
b.HasOne("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluationWorkflowStepInnerStep", null)
.WithMany()
.HasForeignKey("InnerStepId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluation", "PurchaseEvaluation")
.WithMany("DepartmentApprovals")
.HasForeignKey("PurchaseEvaluationId")
@ -3610,6 +3496,11 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
modelBuilder.Entity("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluationWorkflowStep", b =>
{
b.HasOne("SolutionErp.Domain.Master.Department", null)
.WithMany()
.HasForeignKey("DepartmentId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluationWorkflowDefinition", "Definition")
.WithMany("Steps")
.HasForeignKey("PurchaseEvaluationWorkflowDefinitionId")
@ -3630,23 +3521,6 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Navigation("Step");
});
modelBuilder.Entity("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluationWorkflowStepInnerStep", b =>
{
b.HasOne("SolutionErp.Domain.Master.Department", null)
.WithMany()
.HasForeignKey("DepartmentId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluationWorkflowStep", "Step")
.WithMany("InnerSteps")
.HasForeignKey("PurchaseEvaluationWorkflowStepId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Step");
});
modelBuilder.Entity("SolutionErp.Domain.Budgets.Budget", b =>
{
b.Navigation("Approvals");
@ -3693,8 +3567,6 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowStep", b =>
{
b.Navigation("Approvers");
b.Navigation("InnerSteps");
});
modelBuilder.Entity("SolutionErp.Domain.Identity.MenuItem", b =>
@ -3736,8 +3608,6 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
modelBuilder.Entity("SolutionErp.Domain.PurchaseEvaluations.PurchaseEvaluationWorkflowStep", b =>
{
b.Navigation("Approvers");
b.Navigation("InnerSteps");
});
#pragma warning restore 612, 618
}