# sub-test-specialist-0 — TEST-C: PE lũy kế TẠM TÍNH (S134) ## Nhiệm vụ Viết test cho code BE ĐÃ LAND (INV-2): `PeBudgetAccumulator.ComputePendingAsync` + `PeBudgetSummaryDto` +5 field + D4 changelog on-finalize. C1-C9. KHÔNG touch prod. ## Bước 1 — Đọc code under test (DONE) - `tests/.../Services/PeBudgetFreezeTests.cs` — seed-helper pattern :277-336 (SeedWinnerQuoteAsync, SeedPeerAsync CreatedAt-override thủ công :332), T0 flow finalize path, T7 frozen query :730, C8-mirror pattern (Changelog discriminator). - `src/Backend/SolutionErp.Application/PurchaseEvaluations/PeBudgetAccumulator.cs`: - `ComputePendingAsync` :92-139 — peers window Y HỆT ComputeAsync (:100-102: ProjectId+WorkItemId, Id!=peId, CreatedAt0 → +1 Changelog {EntityType=Workflow, Action=Update, PhaseAtChange=DaDuyet, UserId=null, UserName="Hệ thống", ContextNote chứa "[S134 pending-prior]" + priorList (MaPhieu + label)}. - Phase enum: DangSoanThao=1, legacy 2-6, DaDuyet=7, ChoDuyet=10, TraLai=98, TuChoi=99. - BaseEntity.CreatedAt = plain DateTime no-default → phải override thủ công + peCreatedAt muộn hơn. - Helpers khả dụng cùng ns Services: NoOpNotificationService, FixedDateTime, TestCurrentUser, IdentityFixture. ## Bước 3 — viết PePendingAccumulationTests.cs (DONE) File MỚI `tests/SolutionErp.Infrastructure.Tests/Services/PePendingAccumulationTests.cs` — 8 [Fact] C1-C8, mirror seed-helper PeBudgetFreezeTests. Helper copy: CreateService, SeedProjectAndWorkItemAsync, SeedPairAsync (CCM-only), SeedWinnerQuoteAsync, SeedPeerAsync (return peer), SeedFinalizeWorkflowAsync, BuildPeAtFinalizeSlot, ApproveWithPriceAsync, ComputePendingAsync convenience (synthetic curPeId + CurCreatedAt=noon). | Test | Method | Kết quả | |---|---|---| | C1 | `ChoDuyetWinner_CountsInPendingSelected_AndListedInPriorPes` :158 | PendingSelected=70tr/1, Submitted=0, PriorPes Id+MaPhieu+Phase=10 | | C2 | `TuChoiAndDaDuyetPeers_ContributeNothingToPending_AndAbsentFromPriorPes` :185 | delta all 0, PriorPes empty | | C3 | `DraftPeer_ListOnly_TraLaiPeer_CountsInPendingSubmitted` :208 | Submitted=60tr(TraLai)/1 (Nháp 40tr list-only), PriorPes 2 order CreatedAt | | C4 | `PeerCreatedAfterCurrent_ExcludedFromWindow` :234 | before lọt (25tr/1), after loại (NotContain) | | C5 | `NegativeSelectedQuote_ProducesSignedPendingSelectedTotal` :257 | PendingSelected=-500k signed | | C6 | `Compute_And_ComputePending_AreComplementary_NoDoubleCount` :278 | ComputeAsync PrevSelected=90tr/1 PrevSubmitted=130tr/2 bất động; Pending Selected=50tr/1 Submitted=0 | | C7 | `FrozenQuery_ReturnsZeroPendingAndNullPriorPes_EvenWithPendingPeer` :312 | BudgetFrozen=true, Pending 4=0, PriorPes null (dù có peer ChoDuyet) | | C8 | `Finalize_WithPendingPriorPeer_WritesAuditChangelog_ContrastNoPeerWritesNone` :355 | +1 D4 Update/Workflow/UserId=null/Hệ thống/ContextNote⊇MaPhieu A; contrast=0 | ## Bước 4 — chạy suite (DONE) - Filtered `~PePendingAccumulationTests`: **Passed 8/8, Failed 0** (3s). - FULL `dotnet test SolutionErp.slnx --nologo --verbosity minimal -p:BuildInParallel=false -maxcpucount:1`: - Domain **45 PASS** 0 fail; Infra **483 PASS** 0 fail → **528 total, 0 fail**. - Baseline 520 (45D+475I) → **528 (45D+483I) = +8 Infra**. C9 PASS. - Build 0 error. KHÔNG touch production. KHÔNG git add/commit/push. NO prod bug found.