diff --git a/tests/SolutionErp.Infrastructure.Tests/Services/PurchaseEvaluationWorkflowServiceReturnModeTests.cs b/tests/SolutionErp.Infrastructure.Tests/Services/PurchaseEvaluationWorkflowServiceReturnModeTests.cs index 33a9f92..f684e2c 100644 --- a/tests/SolutionErp.Infrastructure.Tests/Services/PurchaseEvaluationWorkflowServiceReturnModeTests.cs +++ b/tests/SolutionErp.Infrastructure.Tests/Services/PurchaseEvaluationWorkflowServiceReturnModeTests.cs @@ -325,12 +325,15 @@ public class PurchaseEvaluationWorkflowServiceReturnModeTests } [Fact] - public async Task ApproveV2_SkipToFinal_AdminTickFlag_SetsPhaseDaDuyet() + public async Task ApproveV2_SkipToFinal_AdminTickFlag_AdvancesToLastSlot() { - // Happy path: workflow 2 Step × 2 Level. Slot Cấp 1 Bước 1 admin tick - // AllowApproverSkipToFinal=true. Actor = userA (Cấp 1 Bước 1 approver, - // non-admin role). PE pin workflow + Phase=ChoDuyet + pointer init Step 0 Cấp 1. - // → Phase=DaDuyet, pointer cleared, opinion + PEA + Changelog logged. + // Happy path (L1 S23 t2 semantic refactor): workflow 2 Step × 2 Level. + // Slot Cấp 1 Bước 1 admin tick AllowApproverSkipToFinal=true. Actor = userA + // (Cấp 1 Bước 1 approver, non-admin role). PE pin workflow + Phase=ChoDuyet + // + pointer init Step 0 Cấp 1. + // → Phase GIỮ ChoDuyet, pointer advance tới last Step (idx=1) + last Level + // (Order=2), opinion + PEA + Changelog logged. NV cuối vẫn cần ký thật để + // tiến DaDuyet (KHÔNG auto-approve terminal — S23 t2 fix bro UAT). var (svc, fix, db, _) = CreateService(); using (fix) { @@ -372,10 +375,10 @@ public class PurchaseEvaluationWorkflowServiceReturnModeTests skipToFinal: true, ct: CancellationToken.None); - pe.Phase.Should().Be(PurchaseEvaluationPhase.DaDuyet, "Skip → terminal trực tiếp"); - pe.CurrentWorkflowStepIndex.Should().BeNull("Pointer cleared khi terminal"); - pe.CurrentApprovalLevelOrder.Should().BeNull("Pointer cleared khi terminal"); - pe.SlaDeadline.Should().BeNull("SLA cleared khi terminal"); + pe.Phase.Should().Be(PurchaseEvaluationPhase.ChoDuyet, "L1 S23 t2: skip advance pointer, NV cuối duyệt thật để DaDuyet"); + pe.CurrentWorkflowStepIndex.Should().Be(1, "Pointer advance tới lastStepIdx (Bước cuối)"); + pe.CurrentApprovalLevelOrder.Should().Be(2, "Pointer advance tới lastLevelMaxOrder (Cấp cuối Bước cuối)"); + pe.SlaDeadline.Should().NotBeNull("SLA reset 7d cho NV cuối nhận lại"); // 1 PEL opinion UPSERT cho slot Cấp 1 Bước 1 trước skip var opinions = await db.PurchaseEvaluationLevelOpinions @@ -391,11 +394,11 @@ public class PurchaseEvaluationWorkflowServiceReturnModeTests approvals[0].ApproverUserId.Should().Be(userA.Id); approvals[0].Decision.Should().Be(ApprovalDecision.Approve); - // Changelog entry với context note chứa "Approver duyệt thẳng Cấp cuối" + // Changelog entry với context note chứa "Approver skip thẳng" + "Bước/Cấp" var changelogs = await db.PurchaseEvaluationChangelogs .Where(c => c.PurchaseEvaluationId == pe.Id).ToListAsync(); changelogs.Should().Contain(c => c.ContextNote != null - && c.ContextNote.Contains("Approver duyệt thẳng Cấp cuối")); + && c.ContextNote.Contains("Approver skip thẳng")); } } @@ -463,9 +466,11 @@ public class PurchaseEvaluationWorkflowServiceReturnModeTests [Fact] public async Task ApproveV2_SkipToFinal_FlagOff_Admin_BypassesFlagCheck() { - // Admin bypass: workflow same nhưng AllowApproverSkipToFinal=false cho slot Cấp 1 Bước 1. - // Actor = adminUser (actorRoles contains "Admin"), trong slot Cấp 1 Bước 1. - // → DaDuyet (admin bypass flag), pointer cleared, opinion logged, Changelog "Approver duyệt thẳng Cấp cuối". + // Admin bypass (L1 S23 t2 semantic): workflow same nhưng AllowApproverSkipToFinal=false + // cho slot Cấp 1 Bước 1. Actor = adminUser (actorRoles contains "Admin"), trong slot. + // → Phase GIỮ ChoDuyet, pointer advance tới last slot (idx=1, Order=2), + // opinion logged, Changelog "Approver skip thẳng". Admin bypass flag check + // — NV cuối vẫn cần ký thật để DaDuyet. var (svc, fix, db, _) = CreateService(); using (fix) { @@ -507,20 +512,20 @@ public class PurchaseEvaluationWorkflowServiceReturnModeTests skipToFinal: true, ct: CancellationToken.None); - pe.Phase.Should().Be(PurchaseEvaluationPhase.DaDuyet, "Admin bypass flag → terminal"); - pe.CurrentWorkflowStepIndex.Should().BeNull("Pointer cleared"); - pe.CurrentApprovalLevelOrder.Should().BeNull("Pointer cleared"); + pe.Phase.Should().Be(PurchaseEvaluationPhase.ChoDuyet, "L1 S23 t2: skip advance pointer, NV cuối duyệt thật"); + pe.CurrentWorkflowStepIndex.Should().Be(1, "Pointer advance tới lastStepIdx"); + pe.CurrentApprovalLevelOrder.Should().Be(2, "Pointer advance tới lastLevelMaxOrder"); // Opinion logged (UPSERT trước skip) var opinions = await db.PurchaseEvaluationLevelOpinions .Where(o => o.PurchaseEvaluationId == pe.Id).ToListAsync(); opinions.Should().HaveCount(1); - // Changelog entry với "Approver duyệt thẳng Cấp cuối" + // Changelog entry với "Approver skip thẳng" var changelogs = await db.PurchaseEvaluationChangelogs .Where(c => c.PurchaseEvaluationId == pe.Id).ToListAsync(); changelogs.Should().Contain(c => c.ContextNote != null - && c.ContextNote.Contains("Approver duyệt thẳng Cấp cuối")); + && c.ContextNote.Contains("Approver skip thẳng")); } }