[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:
pqhuy1987
2026-05-07 12:30:59 +07:00
parent d04bd88fbe
commit ecd5f7e9d9
7 changed files with 3674 additions and 0 deletions

View File

@ -19,6 +19,8 @@ public class ContractConfiguration : IEntityTypeConfiguration<Contract>
b.Property(x => x.TenHopDong).HasMaxLength(500);
b.Property(x => x.NoiDung).HasMaxLength(2000);
b.Property(x => x.DraftData).HasColumnType("nvarchar(max)");
b.Property(x => x.BudgetManualName).HasMaxLength(200);
b.Property(x => x.BudgetManualAmount).HasPrecision(18, 2);
b.HasIndex(x => x.MaHopDong).IsUnique().HasFilter("[MaHopDong] IS NOT NULL");
b.HasIndex(x => new { x.Phase, x.IsDeleted });

View File

@ -19,6 +19,8 @@ public class PurchaseEvaluationConfiguration : IEntityTypeConfiguration<Purchase
b.Property(x => x.DiaDiem).HasMaxLength(500);
b.Property(x => x.MoTa).HasMaxLength(2000);
b.Property(x => x.PaymentTerms).HasColumnType("nvarchar(max)");
b.Property(x => x.BudgetManualName).HasMaxLength(200);
b.Property(x => x.BudgetManualAmount).HasPrecision(18, 2);
b.HasIndex(x => x.MaPhieu).IsUnique().HasFilter("[MaPhieu] IS NOT NULL");
b.HasIndex(x => new { x.Phase, x.IsDeleted });

View File

@ -0,0 +1,64 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SolutionErp.Infrastructure.Persistence.Migrations
{
/// <inheritdoc />
public partial class AddManualBudgetFieldsToPeAndContract : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<decimal>(
name: "BudgetManualAmount",
table: "PurchaseEvaluations",
type: "decimal(18,2)",
precision: 18,
scale: 2,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "BudgetManualName",
table: "PurchaseEvaluations",
type: "nvarchar(200)",
maxLength: 200,
nullable: true);
migrationBuilder.AddColumn<decimal>(
name: "BudgetManualAmount",
table: "Contracts",
type: "decimal(18,2)",
precision: 18,
scale: 2,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "BudgetManualName",
table: "Contracts",
type: "nvarchar(200)",
maxLength: 200,
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "BudgetManualAmount",
table: "PurchaseEvaluations");
migrationBuilder.DropColumn(
name: "BudgetManualName",
table: "PurchaseEvaluations");
migrationBuilder.DropColumn(
name: "BudgetManualAmount",
table: "Contracts");
migrationBuilder.DropColumn(
name: "BudgetManualName",
table: "Contracts");
}
}
}

View File

@ -467,6 +467,14 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<Guid?>("BudgetId")
.HasColumnType("uniqueidentifier");
b.Property<decimal?>("BudgetManualAmount")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("BudgetManualName")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("BypassProcurementAndCCM")
.HasColumnType("bit");
@ -2328,6 +2336,14 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<Guid?>("BudgetId")
.HasColumnType("uniqueidentifier");
b.Property<decimal?>("BudgetManualAmount")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("BudgetManualName")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<Guid?>("ContractId")
.HasColumnType("uniqueidentifier");