[CLAUDE] Domain+Infra: 7 ContractType-specific Details + ContractChangelog (migration 9)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m37s

User decision: Option B — bảng riêng cho mỗi loại HĐ (chuẩn nhất, schema
chuyên biệt). Plus: ContractChangelog audit log thống nhất Header /
Detail / Workflow / Comment / Attachment.

## 8 entities mới

### Details (7) — Domain/Contracts/Details/

| Bảng | Loại HĐ | Field đặc trưng |
|---|---|---|
| ThauPhuDetails | 1 (Thầu phụ) | HangMuc, KhoiLuong, DonGia, ThoiGianHoanThanh |
| GiaoKhoanDetails | 2 (Giao khoán) | MaCongViec, KhoiLuong, YeuCauKyThuat |
| NhaCungCapDetails | 3 (NCC) | MaSP, ThongSoKyThuat, SoLuong, ThoiGianGiao, XuatXu |
| DichVuDetails | 4 (Dịch vụ) | MaDichVu, ThoiGian, TuNgay/DenNgay |
| MuaBanDetails | 5 (Mua bán) | MaSP, SoLuong, DonGia, ThueVAT (%), XuatXu |
| NguyenTacNccDetails | 6 (Nguyên tắc NCC) | NhomSP, DonGiaToiThieu/ToiDa, DieuKienGiaoHang |
| NguyenTacDvDetails | 7 (Nguyên tắc DV) | LoaiDichVu, DonGiaToiThieu/ToiDa, PhamViDichVu, SLA |

Common base `ContractDetailBase`: ContractId FK + Order + ThanhTien
decimal(18,2) + GhiChu nvarchar(1000) + audit (BaseEntity).

### ContractChangelog (1) — Domain/Contracts/

Unified audit log. Khác ContractApprovals (workflow-only, dùng cho guard
logic) — Changelog là VIEW LAYER cho user đọc lịch sử thao tác:
- EntityType enum: Contract | Detail | Workflow | Comment | Attachment
- Action enum: Insert | Update | Delete | Transition
- PhaseAtChange snapshot
- UserId + UserName denormalize (log readable)
- Summary human-readable + FieldChangesJson [{Field, Old, New}]
- ContextNote (comment kèm theo)

## EF Configurations

ContractDetailsConfiguration.cs (1 file gộp 7 IEntityTypeConfiguration):
- ToTable + HasMaxLength + HasPrecision per type
- HasOne(Contract).WithMany(<TypeDetails>) cascade delete
- IX (ContractId, Order) cho load timeline

ContractChangelogConfiguration.cs:
- Cascade delete khi Contract xóa
- IX (ContractId, CreatedAt) timeline + IX (ContractId, EntityType) filter

## DbContext + IApplicationDbContext

+ 8 DbSet mới (7 Details + ContractChangelogs).

## Migration 9: AddContractDetailsAndChangelog

3-file rule (gotcha #17): .cs + .Designer.cs + ApplicationDbContextModel
Snapshot.cs đầy đủ. Applied LocalDB SolutionErp_Dev OK — 24 + 8 = 32 bảng
total.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-04-23 10:08:42 +07:00
parent d326e80082
commit 70810e1b34
17 changed files with 3327 additions and 0 deletions

View File

@ -0,0 +1,344 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SolutionErp.Infrastructure.Persistence.Migrations
{
/// <inheritdoc />
public partial class AddContractDetailsAndChangelog : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ContractChangelogs",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ContractId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
EntityType = table.Column<int>(type: "int", nullable: false),
EntityId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Action = table.Column<int>(type: "int", nullable: false),
PhaseAtChange = table.Column<int>(type: "int", nullable: true),
UserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UserName = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
Summary = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
FieldChangesJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
ContextNote = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ContractChangelogs", x => x.Id);
table.ForeignKey(
name: "FK_ContractChangelogs_Contracts_ContractId",
column: x => x.ContractId,
principalTable: "Contracts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "DichVuDetails",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MaDichVu = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
TenDichVu = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
MoTa = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
DonViTinh = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
ThoiGian = table.Column<decimal>(type: "decimal(18,4)", precision: 18, scale: 4, nullable: false),
DonGia = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
TuNgay = table.Column<DateTime>(type: "datetime2", nullable: true),
DenNgay = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ContractId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Order = table.Column<int>(type: "int", nullable: false),
ThanhTien = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
GhiChu = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_DichVuDetails", x => x.Id);
table.ForeignKey(
name: "FK_DichVuDetails_Contracts_ContractId",
column: x => x.ContractId,
principalTable: "Contracts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "GiaoKhoanDetails",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MaCongViec = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
TenCongViec = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
DonViTinh = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
KhoiLuong = table.Column<decimal>(type: "decimal(18,4)", precision: 18, scale: 4, nullable: false),
DonGia = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
ThoiGianHoanThanh = table.Column<DateTime>(type: "datetime2", nullable: true),
YeuCauKyThuat = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ContractId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Order = table.Column<int>(type: "int", nullable: false),
ThanhTien = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
GhiChu = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_GiaoKhoanDetails", x => x.Id);
table.ForeignKey(
name: "FK_GiaoKhoanDetails_Contracts_ContractId",
column: x => x.ContractId,
principalTable: "Contracts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "MuaBanDetails",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MaSP = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
TenSP = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
MoTa = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
DonViTinh = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
SoLuong = table.Column<decimal>(type: "decimal(18,4)", precision: 18, scale: 4, nullable: false),
DonGia = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
ThueVAT = table.Column<decimal>(type: "decimal(5,2)", precision: 5, scale: 2, nullable: false),
XuatXu = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ContractId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Order = table.Column<int>(type: "int", nullable: false),
ThanhTien = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
GhiChu = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_MuaBanDetails", x => x.Id);
table.ForeignKey(
name: "FK_MuaBanDetails_Contracts_ContractId",
column: x => x.ContractId,
principalTable: "Contracts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "NguyenTacDvDetails",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
LoaiDichVu = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
TenDichVu = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
DonViTinh = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
DonGiaToiThieu = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
DonGiaToiDa = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
PhamViDichVu = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
SLA = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ContractId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Order = table.Column<int>(type: "int", nullable: false),
ThanhTien = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
GhiChu = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_NguyenTacDvDetails", x => x.Id);
table.ForeignKey(
name: "FK_NguyenTacDvDetails_Contracts_ContractId",
column: x => x.ContractId,
principalTable: "Contracts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "NguyenTacNccDetails",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
NhomSP = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
TenSP = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
DonViTinh = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
DonGiaToiThieu = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
DonGiaToiDa = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
DieuKienGiaoHang = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
DieuKienThanhToan = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ContractId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Order = table.Column<int>(type: "int", nullable: false),
ThanhTien = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
GhiChu = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_NguyenTacNccDetails", x => x.Id);
table.ForeignKey(
name: "FK_NguyenTacNccDetails_Contracts_ContractId",
column: x => x.ContractId,
principalTable: "Contracts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "NhaCungCapDetails",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MaSP = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
TenSP = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
ThongSoKyThuat = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
DonViTinh = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
SoLuong = table.Column<decimal>(type: "decimal(18,4)", precision: 18, scale: 4, nullable: false),
DonGia = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
ThoiGianGiao = table.Column<DateTime>(type: "datetime2", nullable: true),
XuatXu = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ContractId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Order = table.Column<int>(type: "int", nullable: false),
ThanhTien = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
GhiChu = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_NhaCungCapDetails", x => x.Id);
table.ForeignKey(
name: "FK_NhaCungCapDetails_Contracts_ContractId",
column: x => x.ContractId,
principalTable: "Contracts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ThauPhuDetails",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
HangMuc = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
DonViTinh = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
KhoiLuong = table.Column<decimal>(type: "decimal(18,4)", precision: 18, scale: 4, nullable: false),
DonGia = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
ThoiGianHoanThanh = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ContractId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Order = table.Column<int>(type: "int", nullable: false),
ThanhTien = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
GhiChu = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ThauPhuDetails", x => x.Id);
table.ForeignKey(
name: "FK_ThauPhuDetails_Contracts_ContractId",
column: x => x.ContractId,
principalTable: "Contracts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ContractChangelogs_ContractId_CreatedAt",
table: "ContractChangelogs",
columns: new[] { "ContractId", "CreatedAt" });
migrationBuilder.CreateIndex(
name: "IX_ContractChangelogs_ContractId_EntityType",
table: "ContractChangelogs",
columns: new[] { "ContractId", "EntityType" });
migrationBuilder.CreateIndex(
name: "IX_DichVuDetails_ContractId_Order",
table: "DichVuDetails",
columns: new[] { "ContractId", "Order" });
migrationBuilder.CreateIndex(
name: "IX_GiaoKhoanDetails_ContractId_Order",
table: "GiaoKhoanDetails",
columns: new[] { "ContractId", "Order" });
migrationBuilder.CreateIndex(
name: "IX_MuaBanDetails_ContractId_Order",
table: "MuaBanDetails",
columns: new[] { "ContractId", "Order" });
migrationBuilder.CreateIndex(
name: "IX_NguyenTacDvDetails_ContractId_Order",
table: "NguyenTacDvDetails",
columns: new[] { "ContractId", "Order" });
migrationBuilder.CreateIndex(
name: "IX_NguyenTacNccDetails_ContractId_Order",
table: "NguyenTacNccDetails",
columns: new[] { "ContractId", "Order" });
migrationBuilder.CreateIndex(
name: "IX_NhaCungCapDetails_ContractId_Order",
table: "NhaCungCapDetails",
columns: new[] { "ContractId", "Order" });
migrationBuilder.CreateIndex(
name: "IX_ThauPhuDetails_ContractId_Order",
table: "ThauPhuDetails",
columns: new[] { "ContractId", "Order" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ContractChangelogs");
migrationBuilder.DropTable(
name: "DichVuDetails");
migrationBuilder.DropTable(
name: "GiaoKhoanDetails");
migrationBuilder.DropTable(
name: "MuaBanDetails");
migrationBuilder.DropTable(
name: "NguyenTacDvDetails");
migrationBuilder.DropTable(
name: "NguyenTacNccDetails");
migrationBuilder.DropTable(
name: "NhaCungCapDetails");
migrationBuilder.DropTable(
name: "ThauPhuDetails");
}
}
}

View File

@ -321,6 +321,66 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.ToTable("ContractAttachments", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractChangelog", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<int>("Action")
.HasColumnType("int");
b.Property<string>("ContextNote")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<Guid>("ContractId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("EntityId")
.HasColumnType("uniqueidentifier");
b.Property<int>("EntityType")
.HasColumnType("int");
b.Property<string>("FieldChangesJson")
.HasColumnType("nvarchar(max)");
b.Property<int?>("PhaseAtChange")
.HasColumnType("int");
b.Property<string>("Summary")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("UserId")
.HasColumnType("uniqueidentifier");
b.Property<string>("UserName")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("ContractId", "CreatedAt");
b.HasIndex("ContractId", "EntityType");
b.ToTable("ContractChangelogs", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractCodeSequence", b =>
{
b.Property<string>("Prefix")
@ -377,6 +437,494 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.ToTable("ContractComments", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.DichVuDetail", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<Guid>("ContractId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<DateTime?>("DenNgay")
.HasColumnType("datetime2");
b.Property<decimal>("DonGia")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("DonViTinh")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("GhiChu")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("MaDichVu")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("MoTa")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<string>("TenDichVu")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<decimal>("ThanhTien")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<decimal>("ThoiGian")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<DateTime?>("TuNgay")
.HasColumnType("datetime2");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("ContractId", "Order");
b.ToTable("DichVuDetails", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.GiaoKhoanDetail", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<Guid>("ContractId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<decimal>("DonGia")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("DonViTinh")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("GhiChu")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<decimal>("KhoiLuong")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<string>("MaCongViec")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<string>("TenCongViec")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<decimal>("ThanhTien")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<DateTime?>("ThoiGianHoanThanh")
.HasColumnType("datetime2");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.Property<string>("YeuCauKyThuat")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.HasKey("Id");
b.HasIndex("ContractId", "Order");
b.ToTable("GiaoKhoanDetails", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.MuaBanDetail", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<Guid>("ContractId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<decimal>("DonGia")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("DonViTinh")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("GhiChu")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("MaSP")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("MoTa")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<decimal>("SoLuong")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<string>("TenSP")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<decimal>("ThanhTien")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<decimal>("ThueVAT")
.HasPrecision(5, 2)
.HasColumnType("decimal(5,2)");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.Property<string>("XuatXu")
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.HasKey("Id");
b.HasIndex("ContractId", "Order");
b.ToTable("MuaBanDetails", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.NguyenTacDvDetail", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<Guid>("ContractId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<decimal>("DonGiaToiDa")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<decimal>("DonGiaToiThieu")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("DonViTinh")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("GhiChu")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("LoaiDichVu")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<string>("PhamViDichVu")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("SLA")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("TenDichVu")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<decimal>("ThanhTien")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("ContractId", "Order");
b.ToTable("NguyenTacDvDetails", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.NguyenTacNccDetail", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<Guid>("ContractId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<string>("DieuKienGiaoHang")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("DieuKienThanhToan")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<decimal>("DonGiaToiDa")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<decimal>("DonGiaToiThieu")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("DonViTinh")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("GhiChu")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("NhomSP")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<string>("TenSP")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<decimal>("ThanhTien")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("ContractId", "Order");
b.ToTable("NguyenTacNccDetails", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.NhaCungCapDetail", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<Guid>("ContractId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<decimal>("DonGia")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("DonViTinh")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("GhiChu")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("MaSP")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<decimal>("SoLuong")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<string>("TenSP")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<decimal>("ThanhTien")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<DateTime?>("ThoiGianGiao")
.HasColumnType("datetime2");
b.Property<string>("ThongSoKyThuat")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.Property<string>("XuatXu")
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.HasKey("Id");
b.HasIndex("ContractId", "Order");
b.ToTable("NhaCungCapDetails", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.ThauPhuDetail", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<Guid>("ContractId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<decimal>("DonGia")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("DonViTinh")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("GhiChu")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("HangMuc")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<decimal>("KhoiLuong")
.HasPrecision(18, 4)
.HasColumnType("decimal(18,4)");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<decimal>("ThanhTien")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<DateTime?>("ThoiGianHoanThanh")
.HasColumnType("datetime2");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("ContractId", "Order");
b.ToTable("ThauPhuDetails", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowDefinition", b =>
{
b.Property<Guid>("Id")
@ -1173,6 +1721,17 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Navigation("Contract");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractChangelog", b =>
{
b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract")
.WithMany("Changelogs")
.HasForeignKey("ContractId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Contract");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractComment", b =>
{
b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract")
@ -1184,6 +1743,83 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Navigation("Contract");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.DichVuDetail", b =>
{
b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract")
.WithMany("DichVuDetails")
.HasForeignKey("ContractId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Contract");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.GiaoKhoanDetail", b =>
{
b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract")
.WithMany("GiaoKhoanDetails")
.HasForeignKey("ContractId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Contract");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.MuaBanDetail", b =>
{
b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract")
.WithMany("MuaBanDetails")
.HasForeignKey("ContractId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Contract");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.NguyenTacDvDetail", b =>
{
b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract")
.WithMany("NguyenTacDvDetails")
.HasForeignKey("ContractId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Contract");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.NguyenTacNccDetail", b =>
{
b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract")
.WithMany("NguyenTacNccDetails")
.HasForeignKey("ContractId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Contract");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.NhaCungCapDetail", b =>
{
b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract")
.WithMany("NhaCungCapDetails")
.HasForeignKey("ContractId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Contract");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.ThauPhuDetail", b =>
{
b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract")
.WithMany("ThauPhuDetails")
.HasForeignKey("ContractId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Contract");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowStep", b =>
{
b.HasOne("SolutionErp.Domain.Contracts.WorkflowDefinition", "WorkflowDefinition")
@ -1241,7 +1877,23 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Navigation("Attachments");
b.Navigation("Changelogs");
b.Navigation("Comments");
b.Navigation("DichVuDetails");
b.Navigation("GiaoKhoanDetails");
b.Navigation("MuaBanDetails");
b.Navigation("NguyenTacDvDetails");
b.Navigation("NguyenTacNccDetails");
b.Navigation("NhaCungCapDetails");
b.Navigation("ThauPhuDetails");
});
modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowDefinition", b =>