# Session 2026-05-07 (S14) — PE 3-button workflow Duyệt/Trả lại/Từ chối

**Dev:** Claude
**Duration:** ~1h
**Base commit:** `b06bdce` (sau Session 13 Contract N-stage mirror)
**Final commit:** `0d77698` (+ Task 2 in-progress, không commit)

## Bối cảnh

Sau Session 11+++++++ user thêm Phase TraLai = 98 + FE label/badge. Session 12 bỏ qua wire BE TraLai. Session 14 này user chốt: KHÔNG cần Phase TraLai trung gian (orphan). Thay vào: 3-button approval rõ ràng.

User wording: "Duyệt Trả lại và Từ chối. Từ chối thì xem như phải làm phiếu mới (khóa hết chức năng). Trả lại → đc điều chỉnh → Gửi duyệt."

## Spec chốt

3 hành động cho approver:
- **Duyệt** = forward phase tiếp theo (decision=Approve, target=next phase)
- **Trả lại** = về DangSoanThao + Drafter sửa (decision=Reject, target=DangSoanThao). Smart reject pattern Mig 16 — set RejectedFromPhase + clear N-stage rows tại fromPhase + Drafter resume jump-back tới phase đã reject.
- **Từ chối** = Phase=TuChoi (decision=Reject, target=TuChoi). Phiếu khoá vĩnh viễn (17 handler Mig 16 lock edit khi Phase != DangSoanThao). Drafter phải tạo phiếu mới.

## Implementation (1 commit `0d77698`)

### Domain — `PurchaseEvaluationPolicy.cs`

**NccOnly** + **NccWithPlan** thêm `(X → TuChoi)` transition cho mọi phase trung gian với roles của phase đó:

```csharp
[(ChoPurchasing, TuChoi)] = [Procurement],
[(ChoCCM, TuChoi)] = [CostControl],
[(ChoCEODuyetNCC, TuChoi)] = [Director, AuthorizedSigner],
// + ChoDuAn, ChoCEODuyetPA cho NccWithPlan
```

**FromDefinition** expand: mỗi step (trừ DangSoanThao) thêm `(step.Phase → TuChoi)` với roles step. Trước đây chỉ DangSoanThao→TuChoi (Drafter).

### Service — `PurchaseEvaluationWorkflowService.TransitionAsync`

Reject branch tách 2 case:

```csharp
if (decision == Reject) {
  if (target != TuChoi) {  // "Trả lại"
    RejectedFromPhase = fromPhase
    target = DangSoanThao  // force
    clear N-stage rows tại fromPhase
  }
  // else target=TuChoi: giữ nguyên TuChoi, KHÔNG set RejectedFromPhase, KHÔNG clear N-stage
  // Phiếu khoá vĩnh viễn — không resume.
}
```

### FE — `PeWorkflowPanel.tsx` (admin + user mirror)

3 button rõ ràng:
- "✓ Duyệt → <label phase>" brand (forward)
- "← Trả lại (về Drafter sửa)" red khi `target=DangSoanThao && fromPhase != DangSoanThao`
- "✗ Hủy / Từ chối" red khi `target=TuChoi`

Decision logic FE: `isReject = target=TuChoi || isSendBack`.

Dialog confirm:
- Title rõ theo loại hành động
- Cancel case: warning red "⚠ Phiếu sẽ bị khoá hoàn toàn. Drafter cần tạo phiếu mới nếu muốn làm lại"
- SendBack case: hint amber "Phiếu sẽ về 'Đang soạn thảo'. Drafter có thể sửa rồi trình lại — workflow tự jump tới phase này"

### Tests

- **Rename** `Reject_Sets_RejectedFromPhase_And_Forces_DangSoanThao` → `Reject_To_DangSoanThao_Sets_RejectedFromPhase_TraLai` (change target từ TuChoi → DangSoanThao để test Trả lại pattern)
- **NEW** `Reject_To_TuChoi_Locks_Permanently_No_RejectedFromPhase` — Phase=TuChoi + RejectedFromPhase=null
- **Update** `NStage_Reject_Clears_InnerStep_Rows_At_Phase` target → DangSoanThao

**95 → 96 test pass** (+1 Từ chối).

## Task 2 sample seed — IN-PROGRESS (defer S15+)

User yêu cầu seed sample data N-stage cho Duyệt NCC. Plan:
1. Update `Users.PositionLevel` (1=NV, 2=PP, 3=TP) cho 30 demo user đã seed
2. INSERT N-stage WorkflowDefinition v2 cho DuyetNcc với InnerSteps (PRO + CCM × 3 cấp NV/PP/TP)

Phát hiện gotcha quan trọng:
- `DesignTimeDbContextFactory` hardcoded `SolutionErp_Design` connection string. `dotnet ef database update` từ Session 12-13 thực ra apply lên `_Design` DB, KHÔNG `_Dev` runtime DB.
- Runtime API dùng `_Dev` (appsettings.Development.json `ConnectionStrings:Default`).
- DbInitializer.MigrateAsync chạy khi API startup → auto apply migrations lên `_Dev`.

Đã xử lý:
- `dotnet ef database update --connection "...SolutionErp_Dev..."` apply Mig 9-20 lên `_Dev` (trước chỉ Mig 1-8).
- Start API để DbInitializer auto-seed 30 demo user. API exit 255 sớm khi log buffer full (~100 lines) — seeding dở dang (chỉ seed Roles, chưa Users).

Defer Session 15+ vì cần guidance:
- (a) User manual `dotnet run` API 1 lần hoàn thành seed → Claude resume seed sample N-stage
- (b) Claude resume với output redirect to file (skip log overflow)
- (c) Manual SQL seed users (nhưng PasswordHash phức tạp)

## Verify

- ✅ `dotnet build` 0 error
- ✅ `dotnet test` **96 pass** (54 Domain + 42 Infra)
- ✅ `npm build` fe-admin + fe-user pass
- ⏸ E2E manual UAT — defer cho user thử 3-button trên menu Duyệt PE

## Bug + Fix log

| # | Issue | Fix |
|---|---|---|
| 1 | Test cũ assume target=TuChoi → Service force DangSoanThao | Update tests: 1 rename + change target sang DangSoanThao + 1 NEW test cho Từ chối behavior |
| 2 | DesignTime vs Runtime DB distinction | `--connection` flag override khi `dotnet ef database update` |

## Docs updates

- ✅ STATUS.md — Last updated + Phase summary count + Recently Done row Session 14 (KEEP narrative)
- ✅ HANDOFF.md — TL;DR Session 14 prepend + 5 cảnh báo Session 15+
- ✅ migration-todos.md — Phase 9 + Session 14 block + 2 defer task
- ✅ Session log (file này)
- ⏸ schema-diagram.md §17 Mig 18 / §18 Mig 19 / §19 Mig 20 — defer cron audit 2026-06-01

## Stats cumulative (sau Session 14)

| | Trước S14 | Sau S14 | Diff |
|---|---:|---:|---:|
| BE LOC | ~15700 | ~15800 | +100 |
| API endpoints | ~134 | ~134 | 0 |
| Migrations | 20 | 20 | 0 |
| DB tables | 57 | 57 | 0 |
| FE pages | 32 | 32 | 0 |
| Tests | 95 | **96** | +1 (Từ chối) |
| Docs | ~57 | ~58 | +1 (session log này) |
| Commits | (after S13) | **+1** | `0d77698` |

## Plan organization sau session 14

```
Plan cha: Phase 9 active — UAT
├── Plan con A: Hard blockers (chờ user/ops) — 6 task
├── ...
├── Plan con S12 ✅ DONE: N-stage PE (Mig 18+19, 6 chunk)
├── Plan con S13 ✅ DONE: N-stage Contract (Mig 20, 5 chunk + skip E)
├── Plan con S14 ✅ DONE: PE 3-button workflow (1 commit)
├── Plan con Task 2 ⏸ DEFER: Sample seed N-stage
└── Plan con Defer S15+:
    ├── Budget N-stage (cần versioned WF migration trước)
    ├── Phase TraLai=98 cleanup (orphan, ko gây hại)
    ├── schema-diagram §17-19 Mig 18-20
    └── Skill ef-core-migration / contract-workflow refresh (cron audit)
```

## Handoff

UAT iteration mode. PE 3-button approval ready test. Workflow N-stage Contract + PE backward compat 100% với 2-stage Mig 16.

**Cron audit kế:** 2026-06-01 (~25 ngày).
