[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:
@ -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 });
|
||||
|
||||
@ -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 });
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user