[CLAUDE] PurchaseEvaluation: Chunk B — Mig 31 K2 Approver F2 branch APPROVE STEP + DTO refactor
Service ApproveV2Async +skipToFinal 8th param. APPROVE STEP branch sau UPSERT PEL opinion: check admin OR matchingLevel.AllowApproverSkipToFinal → set Phase=DaDuyet terminal directly, clear pointer + SLA, audit "[Approver duyệt thẳng Cấp cuối — Bước X Cấp Y → DaDuyet]". Non-admin + flag off → ConflictException. ApproveV1LegacyAsync: throw nếu skipToFinal=true non-admin (V1 legacy không hỗ trợ per-Approver-slot flag). Caller TransitionAsync line ~144 pass skipToFinal vào ApproveV2Async. Drafter SUBMIT branch ignore skipToFinal (K1 đã remove F2 Drafter semantic stub) — Mig 31 marker comment cleanup. DTO ApprovalWorkflowOptionsDto +bool AllowApproverSkipToFinal (7th field). DTO PurchaseEvaluationDetailBundleDto -DrafterAllowSkipToFinal field. GetPe handler populate 7 Allow* từ curLevel (Mig 29+30+31 cumulative). Sentinel `var drafterAllowSkipToFinal = false;` cleanup từ K1. IPurchaseEvaluationWorkflowService.cs comment skipToFinal semantic refactor: Drafter from Nháp → Approver during ChoDuyet skip thẳng Cấp cuối. Pattern reusable: feedback_per_nv_permission_scope.md reinforced 3× cumulative (Mig 29 F1+F3 + Mig 30 F4 + Mig 31 F2). Verify: - dotnet build production projects clean (0 err, 2 warnings pre-existing DocxRenderer) - Test fail at K1 expected (test file references removed prop, K7 sẽ fix) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -118,13 +118,10 @@ public class PurchaseEvaluationWorkflowService(
|
||||
}
|
||||
evaluation.Phase = PurchaseEvaluationPhase.ChoDuyet;
|
||||
|
||||
// Mig 31 (S23 t1 Plan K Chunk A) — F2 Drafter SUBMIT skipToFinal branch
|
||||
// REMOVED stub. Semantic refactor: F2 cũ Drafter-skip-from-Nháp → mới
|
||||
// Approver-skip-during-ChoDuyet (storage move sang
|
||||
// ApprovalWorkflowLevels.AllowApproverSkipToFinal per-slot Approver).
|
||||
// TransitionAsync `bool skipToFinal` 8th param KEPT cho K2 sẽ repurpose
|
||||
// to APPROVE STEP branch (line ~393-525 V2 path).
|
||||
// K2 sẽ add Approver F2 branch trong APPROVE STEP (line ~393-525)
|
||||
// Mig 31 (S23 t1 Plan K) — F2 Drafter-skip-from-Nháp semantic deprecated.
|
||||
// skipToFinal param 8th repurpose sang Approver scope ChoDuyet (xem
|
||||
// ApproveV2Async branch). Drafter SUBMIT chạy normal init pointer Step 0
|
||||
// Cấp 1, ignore skipToFinal flag.
|
||||
evaluation.CurrentWorkflowStepIndex = 0;
|
||||
// Chỉ init levelOrder=1 nếu pin schema V2 (ApprovalWorkflowId set).
|
||||
evaluation.CurrentApprovalLevelOrder = evaluation.ApprovalWorkflowId is not null ? 1 : null;
|
||||
@ -139,12 +136,17 @@ public class PurchaseEvaluationWorkflowService(
|
||||
{
|
||||
// Branch: V2 schema mới (ApprovalWorkflowId pin) hay V1 legacy
|
||||
// (WorkflowDefinitionId pin Mig 21).
|
||||
// Mig 31 (S23 t1 Plan K) — skipToFinal repurpose Approver scope ChoDuyet.
|
||||
// V2 path nhận flag, V1 legacy throw nếu non-admin gọi skipToFinal=true.
|
||||
if (evaluation.ApprovalWorkflowId is Guid awId)
|
||||
{
|
||||
await ApproveV2Async(evaluation, awId, actorUserId, actorRoles, isAdmin, isSystem, comment, ct);
|
||||
await ApproveV2Async(evaluation, awId, actorUserId, actorRoles, isAdmin, isSystem, comment, skipToFinal, ct);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (skipToFinal && !isAdmin && !isSystem)
|
||||
throw new ConflictException(
|
||||
"skipToFinal chỉ hỗ trợ phiếu V2 (ApprovalWorkflowsV2). Phiếu V1 legacy không có per-Approver-slot flag.");
|
||||
await ApproveV1LegacyAsync(evaluation, actorUserId, actorRoles, isAdmin, isSystem, comment, ct);
|
||||
}
|
||||
await db.SaveChangesAsync(ct);
|
||||
@ -364,6 +366,8 @@ public class PurchaseEvaluationWorkflowService(
|
||||
}
|
||||
|
||||
// ===== V2 schema (Mig 22-24) — iterate ApprovalWorkflowSteps + Levels =====
|
||||
// Mig 31 (S23 t1 Plan K) — `skipToFinal` 8th param: F2 Approver scope ChoDuyet.
|
||||
// Admin opt-in flag per slot tại matchingLevel.AllowApproverSkipToFinal.
|
||||
private async Task ApproveV2Async(
|
||||
PurchaseEvaluation evaluation,
|
||||
Guid awId,
|
||||
@ -372,6 +376,7 @@ public class PurchaseEvaluationWorkflowService(
|
||||
bool isAdmin,
|
||||
bool isSystem,
|
||||
string? comment,
|
||||
bool skipToFinal,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var aw = await db.ApprovalWorkflows.AsNoTracking()
|
||||
@ -462,6 +467,38 @@ public class PurchaseEvaluationWorkflowService(
|
||||
existingOpinion.SignedByFullName = actorFullName;
|
||||
}
|
||||
|
||||
// Mig 31 (S23 t1 Plan K) — F2 Approver scope ChoDuyet: duyệt thẳng Cấp cuối.
|
||||
// Admin opt-in per slot tại matchingLevel.AllowApproverSkipToFinal. Khi
|
||||
// Approver tick checkbox "Duyệt thẳng Cấp cuối" trong Workspace + admin
|
||||
// đã enable flag cho slot này → bỏ qua mọi Bước/Cấp trung gian còn lại,
|
||||
// set Phase=DaDuyet terminal trực tiếp. Mirror F3+F4 admin opt-in per-
|
||||
// Approver-slot pattern (Mig 29 + Mig 30) reinforced 3× cumulative.
|
||||
// Non-admin + flag off → ConflictException. Admin bypass flag.
|
||||
if (skipToFinal)
|
||||
{
|
||||
if (!isAdmin && !isSystem && !matchingLevel.AllowApproverSkipToFinal)
|
||||
{
|
||||
throw new ConflictException(
|
||||
$"Cấp Approver hiện tại (Bước {currentIdx + 1} Cấp {currentLevelOrder}) " +
|
||||
"chưa được phép duyệt thẳng Cấp cuối. Admin phải tick checkbox " +
|
||||
"'Duyệt thẳng Cấp cuối' trong Workflow Designer cho slot này.");
|
||||
}
|
||||
|
||||
evaluation.Phase = PurchaseEvaluationPhase.DaDuyet;
|
||||
evaluation.CurrentWorkflowStepIndex = null;
|
||||
evaluation.CurrentApprovalLevelOrder = null;
|
||||
evaluation.SlaDeadline = null;
|
||||
await LogTransitionAsync(
|
||||
evaluation,
|
||||
PurchaseEvaluationPhase.ChoDuyet,
|
||||
PurchaseEvaluationPhase.DaDuyet,
|
||||
actorUserId,
|
||||
ApprovalDecision.Approve,
|
||||
$"[Approver duyệt thẳng Cấp cuối — Bước {currentIdx + 1} Cấp {currentLevelOrder} → DaDuyet] {comment ?? ""}".Trim(),
|
||||
ct);
|
||||
return;
|
||||
}
|
||||
|
||||
// Advance: nếu còn cấp tiếp trong Step → levelOrder++; else → next Step + level 1
|
||||
if (currentLevelOrder < maxLevelOrder)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user