Files
solution-erp/.claude/workflows/runs/2026-07-17-S134-pe-luyke-tam-tinh/sub-test-specialist-0.md
2026-07-17 14:27:19 +07:00

4.4 KiB

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, CreatedAt<peCreatedAt).
      • PendingSubmitted :104-112 = Phase NOT IN {DangSoanThao, DaDuyet, ChoDuyet, TuChoi} → Count + SUM(BudgetPeriodAmount ?? 0).
      • PendingSelected :114-126 = Phase NOT IN {DangSoanThao, DaDuyet, TuChoi} AND Suppliers.Any(IsWinner) → Count + SUM(ThanhTien WHERE IsSelected).
      • PriorPes :128-133 = Phase NOT IN {DaDuyet, TuChoi} orderby CreatedAt → PePendingPriorPeDto(Id, MaPhieu, (int)Phase).
    • PePendingAccumulation record struct :31-36.

Bước 2 — DTO + query handler + D4 (DONE)

  • PePendingPriorPeDto(Guid Id, string? MaPhieu, int Phase) @ Dtos/PurchaseEvaluationDtos.cs:324 (ns SolutionErp.Application.PurchaseEvaluations.Dtos).
  • PeBudgetSummaryDto +5 field cuối :362-366 (PendingSubmittedTotal/Count, PendingSelectedTotal/Count, PendingPriorPes default null).
  • Query handler PurchaseEvaluationFeatures.cs: nhánh frozen :930-959 (Pending 4 số = 0 + PendingPriorPes null); nhánh live :961-1000 (fill từ ComputePendingAsync :972).
  • D4 ApplyBudgetSnapshotOnFinalizeAsync @ PurchaseEvaluationWorkflowService.cs:998 — :1025-1053 nếu ComputePendingAsync.PriorPes.Count>0 → +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.