[CLAUDE] Domain+Infra: Migration 17 — manual budget fields cho PE + HĐ
Chunk 1/5 — DB schema + Domain layer cho fallback "user nhập số tiền ngân sách
tay khi chưa link Budget entity" (UAT request 2026-05-07). Áp cho cả PE + HĐ
(mirror logic per user Q3 chốt).
Migration 17 `AddManualBudgetFieldsToPeAndContract` — 4 ALTER:
- PurchaseEvaluations.BudgetManualName nvarchar(200) NULL
- PurchaseEvaluations.BudgetManualAmount decimal(18,2) NULL
- Contracts.BudgetManualName nvarchar(200) NULL
- Contracts.BudgetManualAmount decimal(18,2) NULL
Validation Q2: cả 2 cùng null OK (PE/HĐ chưa có ngân sách gì cả). KHÔNG XOR
với BudgetId — tạm thời cho phép cả 2 cùng có (BE prefer BudgetId nếu set vì
có Phase=DaDuyet guarantee, manual chỉ là fallback hiển thị/note).
Files:
~ Domain/PurchaseEvaluations/PurchaseEvaluation.cs — 2 property mới
~ Domain/Contracts/Contract.cs — 2 property mới
~ Infrastructure/Persistence/Configurations/PurchaseEvaluationConfiguration.cs
— HasMaxLength(200) + HasPrecision(18,2)
~ Infrastructure/Persistence/Configurations/ContractConfiguration.cs — same
+ Migration 17 .cs + .Designer.cs (3-file rule per ef-core-migration skill)
~ ApplicationDbContextModelSnapshot.cs (auto-overwrite)
Verify:
- dotnet ef migrations add → 3 file gen sạch (4 AddColumn Up + 4 DropColumn Down)
- dotnet ef database update → applied LocalDB OK
- dotnet test SolutionErp.slnx → 83 pass (54 Domain + 29 Infra) — không regression
Next: Chunk 2 App CQRS Create/Update commands + DTO + AutoMapper.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -25,6 +25,11 @@ public class Contract : AuditableEntity
|
||||
public bool SlaWarningSent { get; set; } // Flag để không gửi warning 2 lần
|
||||
public Guid? BudgetId { get; set; } // Reference Budget (Phase 7) — đối chiếu chi phí HĐ vs ngân sách
|
||||
|
||||
// Manual budget fields (Phase 9 — Migration 17 mirror PE): user nhập tay khi
|
||||
// KHÔNG link Budget entity. Cả 2 cùng null OK. KHÔNG XOR validate với BudgetId.
|
||||
public string? BudgetManualName { get; set; } // Tên tham chiếu
|
||||
public decimal? BudgetManualAmount { get; set; } // Tổng số tiền nhập tay (đ)
|
||||
|
||||
// Smart reject (Phase 9 — Migration 16): Phase nguồn khi reject. Drafter
|
||||
// sửa lại + trình lại → quay về RejectedFromPhase thay vì DangSoanThao
|
||||
// tuần tự lại từ đầu. Null khi chưa từng reject hoặc đã trình lại xong.
|
||||
|
||||
@ -28,6 +28,14 @@ public class PurchaseEvaluation : AuditableEntity
|
||||
public Guid? ContractId { get; set; } // FK Contracts — set khi user gen HĐ từ phiếu
|
||||
public Guid? BudgetId { get; set; } // FK Budget (Phase 7) — đối chiếu báo giá vs ngân sách gói thầu
|
||||
|
||||
// Manual budget fields (Phase 9 — Migration 17): user nhập tay khi KHÔNG link
|
||||
// Budget entity (vd ngân sách chưa approve hoặc gói nhỏ ko cần workflow ngân
|
||||
// sách riêng). Cả 2 cùng null OK (PE chưa có ngân sách gì cả). KHÔNG validate
|
||||
// XOR với BudgetId — tạm thời cho phép cả 2 cùng có (BE prefer BudgetId nếu
|
||||
// set vì có Phase=DaDuyet guarantee, manual chỉ là fallback hiển thị).
|
||||
public string? BudgetManualName { get; set; } // Tên tham chiếu vd "Tạm tính dự toán T11/2025"
|
||||
public decimal? BudgetManualAmount { get; set; } // Tổng số tiền nhập tay (đ)
|
||||
|
||||
// Smart reject (Phase 9 — Migration 16): Phase nguồn khi reject. Drafter
|
||||
// sửa lại + trình lại → quay về RejectedFromPhase thay vì đi tuần tự.
|
||||
public PurchaseEvaluationPhase? RejectedFromPhase { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user