diff --git a/src/Backend/SolutionErp.Application/Common/Interfaces/IApplicationDbContext.cs b/src/Backend/SolutionErp.Application/Common/Interfaces/IApplicationDbContext.cs index b27610a..aa40f18 100644 --- a/src/Backend/SolutionErp.Application/Common/Interfaces/IApplicationDbContext.cs +++ b/src/Backend/SolutionErp.Application/Common/Interfaces/IApplicationDbContext.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using SolutionErp.Domain.Contracts; +using SolutionErp.Domain.Contracts.Details; using SolutionErp.Domain.Forms; using SolutionErp.Domain.Identity; using SolutionErp.Domain.Master; @@ -21,11 +22,21 @@ public interface IApplicationDbContext DbSet ContractComments { get; } DbSet ContractAttachments { get; } DbSet ContractCodeSequences { get; } + DbSet ContractChangelogs { get; } DbSet Notifications { get; } DbSet WorkflowTypeAssignments { get; } DbSet WorkflowDefinitions { get; } DbSet WorkflowSteps { get; } DbSet WorkflowStepApprovers { get; } + // Per-type Details DbSets (Option B — bảng riêng từng loại HĐ) + DbSet ThauPhuDetails { get; } + DbSet GiaoKhoanDetails { get; } + DbSet NhaCungCapDetails { get; } + DbSet DichVuDetails { get; } + DbSet MuaBanDetails { get; } + DbSet NguyenTacNccDetails { get; } + DbSet NguyenTacDvDetails { get; } + Task SaveChangesAsync(CancellationToken cancellationToken = default); } diff --git a/src/Backend/SolutionErp.Domain/Contracts/Contract.cs b/src/Backend/SolutionErp.Domain/Contracts/Contract.cs index 03d54d9..af2fecb 100644 --- a/src/Backend/SolutionErp.Domain/Contracts/Contract.cs +++ b/src/Backend/SolutionErp.Domain/Contracts/Contract.cs @@ -1,4 +1,5 @@ using SolutionErp.Domain.Common; +using SolutionErp.Domain.Contracts.Details; namespace SolutionErp.Domain.Contracts; @@ -26,4 +27,16 @@ public class Contract : AuditableEntity public List Approvals { get; set; } = new(); public List Comments { get; set; } = new(); public List Attachments { get; set; } = new(); + public List Changelogs { get; set; } = new(); + + // Per-type details — chỉ 1 collection có data tương ứng với Type. Backend + // logic dispatch theo Contract.Type để load đúng bảng. KHÔNG load eager + // tất cả 7 — overhead. CQRS handler tự chọn DbSet theo Type. + public List ThauPhuDetails { get; set; } = new(); + public List GiaoKhoanDetails { get; set; } = new(); + public List NhaCungCapDetails { get; set; } = new(); + public List DichVuDetails { get; set; } = new(); + public List MuaBanDetails { get; set; } = new(); + public List NguyenTacNccDetails { get; set; } = new(); + public List NguyenTacDvDetails { get; set; } = new(); } diff --git a/src/Backend/SolutionErp.Domain/Contracts/ContractChangelog.cs b/src/Backend/SolutionErp.Domain/Contracts/ContractChangelog.cs new file mode 100644 index 0000000..2cf3460 --- /dev/null +++ b/src/Backend/SolutionErp.Domain/Contracts/ContractChangelog.cs @@ -0,0 +1,44 @@ +using SolutionErp.Domain.Common; + +namespace SolutionErp.Domain.Contracts; + +// Audit log thống nhất cho mọi thay đổi liên quan HĐ — Header / Details / +// Workflow transition / Comment / Attachment. Khác `ContractApprovals` (chỉ +// log workflow transitions, dùng cho guard logic) — Changelog là VIEW LAYER +// cho user đọc lịch sử thao tác. +// +// Populate qua MediatR `AuditBehavior` interceptor — auto từ Insert/Update/ +// Delete commands trên Contract + Details (xem Application/Common/Behaviors/ +// AuditBehavior.cs). +public class ContractChangelog : BaseEntity +{ + public Guid ContractId { get; set; } + public Contract? Contract { get; set; } + + public ChangelogEntityType EntityType { get; set; } // Contract | Detail | Workflow | Comment | Attachment + public Guid? EntityId { get; set; } // PK của child entity (null nếu là Contract header) + public ChangelogAction Action { get; set; } // Insert | Update | Delete | Transition + public ContractPhase? PhaseAtChange { get; set; } // Snapshot phase tại thời điểm change + public Guid? UserId { get; set; } // Null = system (vd SLA auto-approve) + public string? UserName { get; set; } // Denormalize cho log readable + public string? Summary { get; set; } // Human-readable: "Đổi giá trị 100M → 150M" + public string? FieldChangesJson { get; set; } // JSON [{Field, OldValue, NewValue}] cho update + public string? ContextNote { get; set; } // Comment khi user kèm theo thay đổi +} + +public enum ChangelogEntityType +{ + Contract = 1, + Detail = 2, + Workflow = 3, + Comment = 4, + Attachment = 5, +} + +public enum ChangelogAction +{ + Insert = 1, + Update = 2, + Delete = 3, + Transition = 4, // Riêng cho workflow phase change +} diff --git a/src/Backend/SolutionErp.Domain/Contracts/Details/ContractDetailBase.cs b/src/Backend/SolutionErp.Domain/Contracts/Details/ContractDetailBase.cs new file mode 100644 index 0000000..4e4caa1 --- /dev/null +++ b/src/Backend/SolutionErp.Domain/Contracts/Details/ContractDetailBase.cs @@ -0,0 +1,18 @@ +using SolutionErp.Domain.Common; + +namespace SolutionErp.Domain.Contracts.Details; + +// Base cho 7 ContractType Details. Mỗi loại HĐ có 1 bảng riêng (Option B +// theo user decision) — schema đặc thù từng loại nhưng share common fields: +// ContractId FK + Order + ThanhTien + GhiChu + audit (CreatedAt/By). +// +// Không dùng EF TPH/TPT inheritance (mỗi subclass là 1 bảng độc lập, không +// chung type discriminator) — mỗi subclass tự khai báo entity ToTable riêng. +public abstract class ContractDetailBase : BaseEntity +{ + public Guid ContractId { get; set; } + public int Order { get; set; } // Thứ tự dòng trong HĐ (1, 2, 3...) + public decimal ThanhTien { get; set; } // Computed/manual entered + public string? GhiChu { get; set; } + public Contract? Contract { get; set; } +} diff --git a/src/Backend/SolutionErp.Domain/Contracts/Details/DichVuDetail.cs b/src/Backend/SolutionErp.Domain/Contracts/Details/DichVuDetail.cs new file mode 100644 index 0000000..4ba13a1 --- /dev/null +++ b/src/Backend/SolutionErp.Domain/Contracts/Details/DichVuDetail.cs @@ -0,0 +1,14 @@ +namespace SolutionErp.Domain.Contracts.Details; + +// Chi tiết HĐ Dịch vụ (Type=4) — gói dịch vụ thuê (vd thuê thiết bị, tư vấn). +public class DichVuDetail : ContractDetailBase +{ + public string MaDichVu { get; set; } = ""; + public string TenDichVu { get; set; } = ""; + public string? MoTa { get; set; } + public string DonViTinh { get; set; } = ""; // Giờ, ngày, tháng, gói + public decimal ThoiGian { get; set; } // Số đơn vị (vd 30 ngày) + public decimal DonGia { get; set; } // Đơn giá / đơn vị + public DateTime? TuNgay { get; set; } + public DateTime? DenNgay { get; set; } +} diff --git a/src/Backend/SolutionErp.Domain/Contracts/Details/GiaoKhoanDetail.cs b/src/Backend/SolutionErp.Domain/Contracts/Details/GiaoKhoanDetail.cs new file mode 100644 index 0000000..b8d0bdf --- /dev/null +++ b/src/Backend/SolutionErp.Domain/Contracts/Details/GiaoKhoanDetail.cs @@ -0,0 +1,13 @@ +namespace SolutionErp.Domain.Contracts.Details; + +// Chi tiết HĐ Giao khoán (Type=2) — gói công việc giao khoán cho tổ đội. +public class GiaoKhoanDetail : ContractDetailBase +{ + public string MaCongViec { get; set; } = ""; // Mã định danh công việc + public string TenCongViec { get; set; } = ""; + public string DonViTinh { get; set; } = ""; + public decimal KhoiLuong { get; set; } + public decimal DonGia { get; set; } + public DateTime? ThoiGianHoanThanh { get; set; } + public string? YeuCauKyThuat { get; set; } // Spec yêu cầu +} diff --git a/src/Backend/SolutionErp.Domain/Contracts/Details/MuaBanDetail.cs b/src/Backend/SolutionErp.Domain/Contracts/Details/MuaBanDetail.cs new file mode 100644 index 0000000..3bb20c2 --- /dev/null +++ b/src/Backend/SolutionErp.Domain/Contracts/Details/MuaBanDetail.cs @@ -0,0 +1,15 @@ +namespace SolutionErp.Domain.Contracts.Details; + +// Chi tiết HĐ Mua bán (Type=5) — danh mục sản phẩm mua bán + thuế VAT. +public class MuaBanDetail : ContractDetailBase +{ + public string MaSP { get; set; } = ""; + public string TenSP { get; set; } = ""; + public string? MoTa { get; set; } + public string DonViTinh { get; set; } = ""; + public decimal SoLuong { get; set; } + public decimal DonGia { get; set; } // Chưa VAT + public decimal ThueVAT { get; set; } // % (vd 10 = 10%) + // ThanhTien (base class) = SoLuong * DonGia * (1 + ThueVAT/100) + public string? XuatXu { get; set; } +} diff --git a/src/Backend/SolutionErp.Domain/Contracts/Details/NguyenTacDvDetail.cs b/src/Backend/SolutionErp.Domain/Contracts/Details/NguyenTacDvDetail.cs new file mode 100644 index 0000000..2550e1e --- /dev/null +++ b/src/Backend/SolutionErp.Domain/Contracts/Details/NguyenTacDvDetail.cs @@ -0,0 +1,13 @@ +namespace SolutionErp.Domain.Contracts.Details; + +// Chi tiết HĐ Nguyên tắc Dịch vụ (Type=7) — framework agreement cho dịch vụ. +public class NguyenTacDvDetail : ContractDetailBase +{ + public string LoaiDichVu { get; set; } = ""; // Phân loại (vd: "Vận chuyển", "Bảo trì") + public string TenDichVu { get; set; } = ""; + public string DonViTinh { get; set; } = ""; + public decimal DonGiaToiThieu { get; set; } + public decimal DonGiaToiDa { get; set; } + public string? PhamViDichVu { get; set; } // Scope of service + public string? SLA { get; set; } // SLA cam kết (vd "24h response") +} diff --git a/src/Backend/SolutionErp.Domain/Contracts/Details/NguyenTacNccDetail.cs b/src/Backend/SolutionErp.Domain/Contracts/Details/NguyenTacNccDetail.cs new file mode 100644 index 0000000..7a12de4 --- /dev/null +++ b/src/Backend/SolutionErp.Domain/Contracts/Details/NguyenTacNccDetail.cs @@ -0,0 +1,15 @@ +namespace SolutionErp.Domain.Contracts.Details; + +// Chi tiết HĐ Nguyên tắc NCC (Type=6) — framework agreement, không cố định +// số lượng, chỉ liệt kê nhóm SP + price range. ThanhTien base class = 0 +// (không cố định), phục vụ tham chiếu khi tạo PO sau này. +public class NguyenTacNccDetail : ContractDetailBase +{ + public string NhomSP { get; set; } = ""; // Nhóm sản phẩm (vd: "Vật tư xây dựng") + public string TenSP { get; set; } = ""; + public string DonViTinh { get; set; } = ""; + public decimal DonGiaToiThieu { get; set; } + public decimal DonGiaToiDa { get; set; } + public string? DieuKienGiaoHang { get; set; } + public string? DieuKienThanhToan { get; set; } +} diff --git a/src/Backend/SolutionErp.Domain/Contracts/Details/NhaCungCapDetail.cs b/src/Backend/SolutionErp.Domain/Contracts/Details/NhaCungCapDetail.cs new file mode 100644 index 0000000..6ec5b00 --- /dev/null +++ b/src/Backend/SolutionErp.Domain/Contracts/Details/NhaCungCapDetail.cs @@ -0,0 +1,14 @@ +namespace SolutionErp.Domain.Contracts.Details; + +// Chi tiết HĐ Nhà cung cấp (Type=3) — danh mục sản phẩm mua từ NCC. +public class NhaCungCapDetail : ContractDetailBase +{ + public string MaSP { get; set; } = ""; // Mã sản phẩm + public string TenSP { get; set; } = ""; + public string? ThongSoKyThuat { get; set; } // Specification + public string DonViTinh { get; set; } = ""; + public decimal SoLuong { get; set; } + public decimal DonGia { get; set; } + public DateTime? ThoiGianGiao { get; set; } // Lead time + public string? XuatXu { get; set; } // Origin country +} diff --git a/src/Backend/SolutionErp.Domain/Contracts/Details/ThauPhuDetail.cs b/src/Backend/SolutionErp.Domain/Contracts/Details/ThauPhuDetail.cs new file mode 100644 index 0000000..aaff693 --- /dev/null +++ b/src/Backend/SolutionErp.Domain/Contracts/Details/ThauPhuDetail.cs @@ -0,0 +1,12 @@ +namespace SolutionErp.Domain.Contracts.Details; + +// Chi tiết HĐ Thầu phụ (Type=1) — line item theo hạng mục công việc thầu phụ. +public class ThauPhuDetail : ContractDetailBase +{ + public string HangMuc { get; set; } = ""; // Tên hạng mục công việc + public string DonViTinh { get; set; } = ""; // m2, m3, kg, ngày công, ... + public decimal KhoiLuong { get; set; } // 4 chữ số thập phân (decimal 18,4) + public decimal DonGia { get; set; } // VND + // ThanhTien = KhoiLuong * DonGia (FE/BE compute, không trigger DB) + public DateTime? ThoiGianHoanThanh { get; set; } +} diff --git a/src/Backend/SolutionErp.Infrastructure/Persistence/ApplicationDbContext.cs b/src/Backend/SolutionErp.Infrastructure/Persistence/ApplicationDbContext.cs index f5eddbb..dd45e88 100644 --- a/src/Backend/SolutionErp.Infrastructure/Persistence/ApplicationDbContext.cs +++ b/src/Backend/SolutionErp.Infrastructure/Persistence/ApplicationDbContext.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using SolutionErp.Application.Common.Interfaces; using SolutionErp.Domain.Contracts; +using SolutionErp.Domain.Contracts.Details; using SolutionErp.Domain.Forms; using SolutionErp.Domain.Identity; using SolutionErp.Domain.Master; @@ -26,11 +27,19 @@ public class ApplicationDbContext public DbSet ContractComments => Set(); public DbSet ContractAttachments => Set(); public DbSet ContractCodeSequences => Set(); + public DbSet ContractChangelogs => Set(); public DbSet Notifications => Set(); public DbSet WorkflowTypeAssignments => Set(); public DbSet WorkflowDefinitions => Set(); public DbSet WorkflowSteps => Set(); public DbSet WorkflowStepApprovers => Set(); + public DbSet ThauPhuDetails => Set(); + public DbSet GiaoKhoanDetails => Set(); + public DbSet NhaCungCapDetails => Set(); + public DbSet DichVuDetails => Set(); + public DbSet MuaBanDetails => Set(); + public DbSet NguyenTacNccDetails => Set(); + public DbSet NguyenTacDvDetails => Set(); protected override void OnModelCreating(ModelBuilder builder) { diff --git a/src/Backend/SolutionErp.Infrastructure/Persistence/Configurations/ContractChangelogConfiguration.cs b/src/Backend/SolutionErp.Infrastructure/Persistence/Configurations/ContractChangelogConfiguration.cs new file mode 100644 index 0000000..74af084 --- /dev/null +++ b/src/Backend/SolutionErp.Infrastructure/Persistence/Configurations/ContractChangelogConfiguration.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using SolutionErp.Domain.Contracts; + +namespace SolutionErp.Infrastructure.Persistence.Configurations; + +public class ContractChangelogConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder b) + { + b.ToTable("ContractChangelogs"); + b.HasKey(x => x.Id); + + b.Property(x => x.EntityType).HasConversion(); + b.Property(x => x.Action).HasConversion(); + b.Property(x => x.PhaseAtChange).HasConversion(); + b.Property(x => x.UserName).HasMaxLength(200); + b.Property(x => x.Summary).HasMaxLength(500); + b.Property(x => x.FieldChangesJson).HasColumnType("nvarchar(max)"); + b.Property(x => x.ContextNote).HasMaxLength(2000); + + b.HasOne(x => x.Contract) + .WithMany(c => c.Changelogs) + .HasForeignKey(x => x.ContractId) + .OnDelete(DeleteBehavior.Cascade); + + // Common queries: all changes của 1 HĐ ordered timeline + b.HasIndex(x => new { x.ContractId, x.CreatedAt }); + // Filter theo entity type (chỉ xem header changes / chỉ workflow / etc.) + b.HasIndex(x => new { x.ContractId, x.EntityType }); + } +} diff --git a/src/Backend/SolutionErp.Infrastructure/Persistence/Configurations/ContractDetailsConfiguration.cs b/src/Backend/SolutionErp.Infrastructure/Persistence/Configurations/ContractDetailsConfiguration.cs new file mode 100644 index 0000000..003407c --- /dev/null +++ b/src/Backend/SolutionErp.Infrastructure/Persistence/Configurations/ContractDetailsConfiguration.cs @@ -0,0 +1,187 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using SolutionErp.Domain.Contracts.Details; + +namespace SolutionErp.Infrastructure.Persistence.Configurations; + +// EF config cho 7 ContractType-specific Details bảng + 1 base abstract. +// Common pattern: ContractId FK Cascade, Order int, ThanhTien decimal(18,2), +// GhiChu nvarchar(1000), index theo (ContractId, Order). + +public class ThauPhuDetailConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder b) + { + b.ToTable("ThauPhuDetails"); + b.HasKey(x => x.Id); + + b.Property(x => x.HangMuc).HasMaxLength(500).IsRequired(); + b.Property(x => x.DonViTinh).HasMaxLength(50).IsRequired(); + b.Property(x => x.KhoiLuong).HasPrecision(18, 4); + b.Property(x => x.DonGia).HasPrecision(18, 2); + b.Property(x => x.ThanhTien).HasPrecision(18, 2); + b.Property(x => x.GhiChu).HasMaxLength(1000); + + b.HasOne(x => x.Contract) + .WithMany(c => c.ThauPhuDetails) + .HasForeignKey(x => x.ContractId) + .OnDelete(DeleteBehavior.Cascade); + + b.HasIndex(x => new { x.ContractId, x.Order }); + } +} + +public class GiaoKhoanDetailConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder b) + { + b.ToTable("GiaoKhoanDetails"); + b.HasKey(x => x.Id); + + b.Property(x => x.MaCongViec).HasMaxLength(100).IsRequired(); + b.Property(x => x.TenCongViec).HasMaxLength(500).IsRequired(); + b.Property(x => x.DonViTinh).HasMaxLength(50).IsRequired(); + b.Property(x => x.KhoiLuong).HasPrecision(18, 4); + b.Property(x => x.DonGia).HasPrecision(18, 2); + b.Property(x => x.ThanhTien).HasPrecision(18, 2); + b.Property(x => x.GhiChu).HasMaxLength(1000); + b.Property(x => x.YeuCauKyThuat).HasMaxLength(2000); + + b.HasOne(x => x.Contract) + .WithMany(c => c.GiaoKhoanDetails) + .HasForeignKey(x => x.ContractId) + .OnDelete(DeleteBehavior.Cascade); + + b.HasIndex(x => new { x.ContractId, x.Order }); + } +} + +public class NhaCungCapDetailConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder b) + { + b.ToTable("NhaCungCapDetails"); + b.HasKey(x => x.Id); + + b.Property(x => x.MaSP).HasMaxLength(100).IsRequired(); + b.Property(x => x.TenSP).HasMaxLength(500).IsRequired(); + b.Property(x => x.ThongSoKyThuat).HasMaxLength(2000); + b.Property(x => x.DonViTinh).HasMaxLength(50).IsRequired(); + b.Property(x => x.SoLuong).HasPrecision(18, 4); + b.Property(x => x.DonGia).HasPrecision(18, 2); + b.Property(x => x.ThanhTien).HasPrecision(18, 2); + b.Property(x => x.GhiChu).HasMaxLength(1000); + b.Property(x => x.XuatXu).HasMaxLength(100); + + b.HasOne(x => x.Contract) + .WithMany(c => c.NhaCungCapDetails) + .HasForeignKey(x => x.ContractId) + .OnDelete(DeleteBehavior.Cascade); + + b.HasIndex(x => new { x.ContractId, x.Order }); + } +} + +public class DichVuDetailConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder b) + { + b.ToTable("DichVuDetails"); + b.HasKey(x => x.Id); + + b.Property(x => x.MaDichVu).HasMaxLength(100).IsRequired(); + b.Property(x => x.TenDichVu).HasMaxLength(500).IsRequired(); + b.Property(x => x.MoTa).HasMaxLength(2000); + b.Property(x => x.DonViTinh).HasMaxLength(50).IsRequired(); + b.Property(x => x.ThoiGian).HasPrecision(18, 4); + b.Property(x => x.DonGia).HasPrecision(18, 2); + b.Property(x => x.ThanhTien).HasPrecision(18, 2); + b.Property(x => x.GhiChu).HasMaxLength(1000); + + b.HasOne(x => x.Contract) + .WithMany(c => c.DichVuDetails) + .HasForeignKey(x => x.ContractId) + .OnDelete(DeleteBehavior.Cascade); + + b.HasIndex(x => new { x.ContractId, x.Order }); + } +} + +public class MuaBanDetailConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder b) + { + b.ToTable("MuaBanDetails"); + b.HasKey(x => x.Id); + + b.Property(x => x.MaSP).HasMaxLength(100).IsRequired(); + b.Property(x => x.TenSP).HasMaxLength(500).IsRequired(); + b.Property(x => x.MoTa).HasMaxLength(2000); + b.Property(x => x.DonViTinh).HasMaxLength(50).IsRequired(); + b.Property(x => x.SoLuong).HasPrecision(18, 4); + b.Property(x => x.DonGia).HasPrecision(18, 2); + b.Property(x => x.ThueVAT).HasPrecision(5, 2); // % + b.Property(x => x.ThanhTien).HasPrecision(18, 2); + b.Property(x => x.GhiChu).HasMaxLength(1000); + b.Property(x => x.XuatXu).HasMaxLength(100); + + b.HasOne(x => x.Contract) + .WithMany(c => c.MuaBanDetails) + .HasForeignKey(x => x.ContractId) + .OnDelete(DeleteBehavior.Cascade); + + b.HasIndex(x => new { x.ContractId, x.Order }); + } +} + +public class NguyenTacNccDetailConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder b) + { + b.ToTable("NguyenTacNccDetails"); + b.HasKey(x => x.Id); + + b.Property(x => x.NhomSP).HasMaxLength(200).IsRequired(); + b.Property(x => x.TenSP).HasMaxLength(500).IsRequired(); + b.Property(x => x.DonViTinh).HasMaxLength(50).IsRequired(); + b.Property(x => x.DonGiaToiThieu).HasPrecision(18, 2); + b.Property(x => x.DonGiaToiDa).HasPrecision(18, 2); + b.Property(x => x.ThanhTien).HasPrecision(18, 2); + b.Property(x => x.DieuKienGiaoHang).HasMaxLength(1000); + b.Property(x => x.DieuKienThanhToan).HasMaxLength(1000); + b.Property(x => x.GhiChu).HasMaxLength(1000); + + b.HasOne(x => x.Contract) + .WithMany(c => c.NguyenTacNccDetails) + .HasForeignKey(x => x.ContractId) + .OnDelete(DeleteBehavior.Cascade); + + b.HasIndex(x => new { x.ContractId, x.Order }); + } +} + +public class NguyenTacDvDetailConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder b) + { + b.ToTable("NguyenTacDvDetails"); + b.HasKey(x => x.Id); + + b.Property(x => x.LoaiDichVu).HasMaxLength(200).IsRequired(); + b.Property(x => x.TenDichVu).HasMaxLength(500).IsRequired(); + b.Property(x => x.DonViTinh).HasMaxLength(50).IsRequired(); + b.Property(x => x.DonGiaToiThieu).HasPrecision(18, 2); + b.Property(x => x.DonGiaToiDa).HasPrecision(18, 2); + b.Property(x => x.ThanhTien).HasPrecision(18, 2); + b.Property(x => x.PhamViDichVu).HasMaxLength(1000); + b.Property(x => x.SLA).HasMaxLength(500); + b.Property(x => x.GhiChu).HasMaxLength(1000); + + b.HasOne(x => x.Contract) + .WithMany(c => c.NguyenTacDvDetails) + .HasForeignKey(x => x.ContractId) + .OnDelete(DeleteBehavior.Cascade); + + b.HasIndex(x => new { x.ContractId, x.Order }); + } +} diff --git a/src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/20260423030733_AddContractDetailsAndChangelog.Designer.cs b/src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/20260423030733_AddContractDetailsAndChangelog.Designer.cs new file mode 100644 index 0000000..e2cdd55 --- /dev/null +++ b/src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/20260423030733_AddContractDetailsAndChangelog.Designer.cs @@ -0,0 +1,1921 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SolutionErp.Infrastructure.Persistence; + +#nullable disable + +namespace SolutionErp.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20260423030733_AddContractDetailsAndChangelog")] + partial class AddContractDetailsAndChangelog + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.Contract", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BypassProcurementAndCCM") + .HasColumnType("bit"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DepartmentId") + .HasColumnType("uniqueidentifier"); + + b.Property("DraftData") + .HasColumnType("nvarchar(max)"); + + b.Property("DrafterUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("GiaTri") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("MaHopDong") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("NoiDung") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("Phase") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("SlaDeadline") + .HasColumnType("datetime2"); + + b.Property("SlaWarningSent") + .HasColumnType("bit"); + + b.Property("SupplierId") + .HasColumnType("uniqueidentifier"); + + b.Property("TemplateId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenHopDong") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("WorkflowDefinitionId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("MaHopDong") + .IsUnique() + .HasFilter("[MaHopDong] IS NOT NULL"); + + b.HasIndex("ProjectId"); + + b.HasIndex("SlaDeadline"); + + b.HasIndex("SupplierId"); + + b.HasIndex("Phase", "IsDeleted"); + + b.ToTable("Contracts", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractApproval", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApprovedAt") + .HasColumnType("datetime2"); + + b.Property("ApproverUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Comment") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("Decision") + .HasColumnType("int"); + + b.Property("FromPhase") + .HasColumnType("int"); + + b.Property("ToPhase") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ContractId", "ApprovedAt"); + + b.ToTable("ContractApprovals", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContentType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Purpose") + .HasColumnType("int"); + + b.Property("StoragePath") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ContractId"); + + b.ToTable("ContractAttachments", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractChangelog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("int"); + + b.Property("ContextNote") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("EntityId") + .HasColumnType("uniqueidentifier"); + + b.Property("EntityType") + .HasColumnType("int"); + + b.Property("FieldChangesJson") + .HasColumnType("nvarchar(max)"); + + b.Property("PhaseAtChange") + .HasColumnType("int"); + + b.Property("Summary") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("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("Prefix") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("LastSeq") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Prefix"); + + b.ToTable("ContractCodeSequences", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("Phase") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ContractId", "CreatedAt"); + + b.ToTable("ContractComments", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.Details.DichVuDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DenNgay") + .HasColumnType("datetime2"); + + b.Property("DonGia") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("MaDichVu") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MoTa") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("TenDichVu") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ThoiGian") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.Property("TuNgay") + .HasColumnType("datetime2"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DonGia") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("KhoiLuong") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.Property("MaCongViec") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("TenCongViec") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ThoiGianHoanThanh") + .HasColumnType("datetime2"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DonGia") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("MaSP") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MoTa") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("SoLuong") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.Property("TenSP") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ThueVAT") + .HasPrecision(5, 2) + .HasColumnType("decimal(5,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DonGiaToiDa") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonGiaToiThieu") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("LoaiDichVu") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("PhamViDichVu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SLA") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("TenDichVu") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DieuKienGiaoHang") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DieuKienThanhToan") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DonGiaToiDa") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonGiaToiThieu") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("NhomSP") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("TenSP") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DonGia") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("MaSP") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("SoLuong") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.Property("TenSP") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ThoiGianGiao") + .HasColumnType("datetime2"); + + b.Property("ThongSoKyThuat") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DonGia") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HangMuc") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("KhoiLuong") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ThoiGianHoanThanh") + .HasColumnType("datetime2"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ContractId", "Order"); + + b.ToTable("ThauPhuDetails", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ActivatedAt") + .HasColumnType("datetime2"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ContractType") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("Version") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Code", "Version") + .IsUnique(); + + b.HasIndex("ContractType", "IsActive"); + + b.ToTable("WorkflowDefinitions", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowStep", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("Phase") + .HasColumnType("int"); + + b.Property("SlaDays") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("WorkflowDefinitionId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("WorkflowDefinitionId", "Order"); + + b.ToTable("WorkflowSteps", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowStepApprover", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AssignmentValue") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("Kind") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("WorkflowStepId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("WorkflowStepId"); + + b.ToTable("WorkflowStepApprovers", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowTypeAssignment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractType") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("PolicyName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ContractType") + .IsUnique(); + + b.ToTable("WorkflowTypeAssignments", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Forms.ContractClause", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Content") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("Version") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("ContractClauses", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Forms.ContractTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractType") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("FieldSpec") + .HasColumnType("nvarchar(max)"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FormCode") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Format") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("StoragePath") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ContractType"); + + b.HasIndex("FormCode") + .IsUnique(); + + b.ToTable("ContractTemplates", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Identity.MenuItem", b => + { + b.Property("Key") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Icon") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("ParentKey") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Key"); + + b.HasIndex("ParentKey"); + + b.ToTable("MenuItems", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Identity.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CanCreate") + .HasColumnType("bit"); + + b.Property("CanDelete") + .HasColumnType("bit"); + + b.Property("CanRead") + .HasColumnType("bit"); + + b.Property("CanUpdate") + .HasColumnType("bit"); + + b.Property("MenuKey") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("MenuKey"); + + b.HasIndex("RoleId", "MenuKey") + .IsUnique(); + + b.ToTable("Permissions", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Identity.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("Roles", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Identity.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("RefreshToken") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("RefreshTokenExpiresAt") + .HasColumnType("datetime2"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Master.Department", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ManagerUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Departments", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Master.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BudgetTotal") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ManagerUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Master.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Address") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ContactPerson") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("DeletedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("Email") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Phone") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("TaxCode") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Code") + .IsUnique(); + + b.HasIndex("Type"); + + b.ToTable("Suppliers", (string)null); + }); + + modelBuilder.Entity("SolutionErp.Domain.Notifications.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Href") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ReadAt") + .HasColumnType("datetime2"); + + b.Property("RefId") + .HasColumnType("uniqueidentifier"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("UserId", "ReadAt"); + + b.ToTable("Notifications", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("SolutionErp.Domain.Identity.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("SolutionErp.Domain.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("SolutionErp.Domain.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("SolutionErp.Domain.Identity.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SolutionErp.Domain.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("SolutionErp.Domain.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractApproval", b => + { + b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract") + .WithMany("Approvals") + .HasForeignKey("ContractId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contract"); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractAttachment", b => + { + b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract") + .WithMany("Attachments") + .HasForeignKey("ContractId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + 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") + .WithMany("Comments") + .HasForeignKey("ContractId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + 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") + .WithMany("Steps") + .HasForeignKey("WorkflowDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("WorkflowDefinition"); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowStepApprover", b => + { + b.HasOne("SolutionErp.Domain.Contracts.WorkflowStep", "Step") + .WithMany("Approvers") + .HasForeignKey("WorkflowStepId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Step"); + }); + + modelBuilder.Entity("SolutionErp.Domain.Identity.MenuItem", b => + { + b.HasOne("SolutionErp.Domain.Identity.MenuItem", "Parent") + .WithMany("Children") + .HasForeignKey("ParentKey") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("SolutionErp.Domain.Identity.Permission", b => + { + b.HasOne("SolutionErp.Domain.Identity.MenuItem", "Menu") + .WithMany("Permissions") + .HasForeignKey("MenuKey") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SolutionErp.Domain.Identity.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Menu"); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.Contract", b => + { + b.Navigation("Approvals"); + + 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 => + { + b.Navigation("Steps"); + }); + + modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowStep", b => + { + b.Navigation("Approvers"); + }); + + modelBuilder.Entity("SolutionErp.Domain.Identity.MenuItem", b => + { + b.Navigation("Children"); + + b.Navigation("Permissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/20260423030733_AddContractDetailsAndChangelog.cs b/src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/20260423030733_AddContractDetailsAndChangelog.cs new file mode 100644 index 0000000..1c65dc9 --- /dev/null +++ b/src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/20260423030733_AddContractDetailsAndChangelog.cs @@ -0,0 +1,344 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SolutionErp.Infrastructure.Persistence.Migrations +{ + /// + public partial class AddContractDetailsAndChangelog : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ContractChangelogs", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ContractId = table.Column(type: "uniqueidentifier", nullable: false), + EntityType = table.Column(type: "int", nullable: false), + EntityId = table.Column(type: "uniqueidentifier", nullable: true), + Action = table.Column(type: "int", nullable: false), + PhaseAtChange = table.Column(type: "int", nullable: true), + UserId = table.Column(type: "uniqueidentifier", nullable: true), + UserName = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), + Summary = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), + FieldChangesJson = table.Column(type: "nvarchar(max)", nullable: true), + ContextNote = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "uniqueidentifier", nullable: true), + UpdatedBy = table.Column(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(type: "uniqueidentifier", nullable: false), + MaDichVu = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + TenDichVu = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: false), + MoTa = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), + DonViTinh = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + ThoiGian = table.Column(type: "decimal(18,4)", precision: 18, scale: 4, nullable: false), + DonGia = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + TuNgay = table.Column(type: "datetime2", nullable: true), + DenNgay = table.Column(type: "datetime2", nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "uniqueidentifier", nullable: true), + UpdatedBy = table.Column(type: "uniqueidentifier", nullable: true), + ContractId = table.Column(type: "uniqueidentifier", nullable: false), + Order = table.Column(type: "int", nullable: false), + ThanhTien = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + GhiChu = table.Column(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(type: "uniqueidentifier", nullable: false), + MaCongViec = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + TenCongViec = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: false), + DonViTinh = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + KhoiLuong = table.Column(type: "decimal(18,4)", precision: 18, scale: 4, nullable: false), + DonGia = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + ThoiGianHoanThanh = table.Column(type: "datetime2", nullable: true), + YeuCauKyThuat = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "uniqueidentifier", nullable: true), + UpdatedBy = table.Column(type: "uniqueidentifier", nullable: true), + ContractId = table.Column(type: "uniqueidentifier", nullable: false), + Order = table.Column(type: "int", nullable: false), + ThanhTien = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + GhiChu = table.Column(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(type: "uniqueidentifier", nullable: false), + MaSP = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + TenSP = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: false), + MoTa = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), + DonViTinh = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + SoLuong = table.Column(type: "decimal(18,4)", precision: 18, scale: 4, nullable: false), + DonGia = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + ThueVAT = table.Column(type: "decimal(5,2)", precision: 5, scale: 2, nullable: false), + XuatXu = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "uniqueidentifier", nullable: true), + UpdatedBy = table.Column(type: "uniqueidentifier", nullable: true), + ContractId = table.Column(type: "uniqueidentifier", nullable: false), + Order = table.Column(type: "int", nullable: false), + ThanhTien = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + GhiChu = table.Column(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(type: "uniqueidentifier", nullable: false), + LoaiDichVu = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + TenDichVu = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: false), + DonViTinh = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + DonGiaToiThieu = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + DonGiaToiDa = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + PhamViDichVu = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + SLA = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "uniqueidentifier", nullable: true), + UpdatedBy = table.Column(type: "uniqueidentifier", nullable: true), + ContractId = table.Column(type: "uniqueidentifier", nullable: false), + Order = table.Column(type: "int", nullable: false), + ThanhTien = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + GhiChu = table.Column(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(type: "uniqueidentifier", nullable: false), + NhomSP = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), + TenSP = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: false), + DonViTinh = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + DonGiaToiThieu = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + DonGiaToiDa = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + DieuKienGiaoHang = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + DieuKienThanhToan = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "uniqueidentifier", nullable: true), + UpdatedBy = table.Column(type: "uniqueidentifier", nullable: true), + ContractId = table.Column(type: "uniqueidentifier", nullable: false), + Order = table.Column(type: "int", nullable: false), + ThanhTien = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + GhiChu = table.Column(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(type: "uniqueidentifier", nullable: false), + MaSP = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + TenSP = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: false), + ThongSoKyThuat = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), + DonViTinh = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + SoLuong = table.Column(type: "decimal(18,4)", precision: 18, scale: 4, nullable: false), + DonGia = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + ThoiGianGiao = table.Column(type: "datetime2", nullable: true), + XuatXu = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "uniqueidentifier", nullable: true), + UpdatedBy = table.Column(type: "uniqueidentifier", nullable: true), + ContractId = table.Column(type: "uniqueidentifier", nullable: false), + Order = table.Column(type: "int", nullable: false), + ThanhTien = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + GhiChu = table.Column(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(type: "uniqueidentifier", nullable: false), + HangMuc = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: false), + DonViTinh = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + KhoiLuong = table.Column(type: "decimal(18,4)", precision: 18, scale: 4, nullable: false), + DonGia = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + ThoiGianHoanThanh = table.Column(type: "datetime2", nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + UpdatedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "uniqueidentifier", nullable: true), + UpdatedBy = table.Column(type: "uniqueidentifier", nullable: true), + ContractId = table.Column(type: "uniqueidentifier", nullable: false), + Order = table.Column(type: "int", nullable: false), + ThanhTien = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + GhiChu = table.Column(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" }); + } + + /// + 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"); + } + } +} diff --git a/src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs index a4458eb..d6ce7bf 100644 --- a/src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs @@ -321,6 +321,66 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations b.ToTable("ContractAttachments", (string)null); }); + modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractChangelog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("int"); + + b.Property("ContextNote") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("EntityId") + .HasColumnType("uniqueidentifier"); + + b.Property("EntityType") + .HasColumnType("int"); + + b.Property("FieldChangesJson") + .HasColumnType("nvarchar(max)"); + + b.Property("PhaseAtChange") + .HasColumnType("int"); + + b.Property("Summary") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("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("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DenNgay") + .HasColumnType("datetime2"); + + b.Property("DonGia") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("MaDichVu") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MoTa") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("TenDichVu") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ThoiGian") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.Property("TuNgay") + .HasColumnType("datetime2"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DonGia") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("KhoiLuong") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.Property("MaCongViec") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("TenCongViec") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ThoiGianHoanThanh") + .HasColumnType("datetime2"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DonGia") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("MaSP") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MoTa") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("SoLuong") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.Property("TenSP") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ThueVAT") + .HasPrecision(5, 2) + .HasColumnType("decimal(5,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DonGiaToiDa") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonGiaToiThieu") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("LoaiDichVu") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("PhamViDichVu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SLA") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("TenDichVu") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DieuKienGiaoHang") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DieuKienThanhToan") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DonGiaToiDa") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonGiaToiThieu") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("NhomSP") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("TenSP") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DonGia") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("MaSP") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("SoLuong") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.Property("TenSP") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ThoiGianGiao") + .HasColumnType("datetime2"); + + b.Property("ThongSoKyThuat") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContractId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("DonGia") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DonViTinh") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("GhiChu") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("HangMuc") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("KhoiLuong") + .HasPrecision(18, 4) + .HasColumnType("decimal(18,4)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("ThanhTien") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ThoiGianHoanThanh") + .HasColumnType("datetime2"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("UpdatedBy") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ContractId", "Order"); + + b.ToTable("ThauPhuDetails", (string)null); + }); + modelBuilder.Entity("SolutionErp.Domain.Contracts.WorkflowDefinition", b => { b.Property("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 =>