[CLAUDE] Domain+App+Api: Module Ngan sach (Budget) - 4 bang + workflow simple
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m11s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m11s
User request: 'Them cho tao 4 bang luu ve ngan sach: Header / Chi tiet
/ Quy trinh duyet / Lich su thay doi'.
Domain (5 file + 1 enum):
- Budget (header) — Aggregate root, AuditableEntity. Field: MaNganSach,
TenNganSach, Description, NamNganSach, ProjectId FK, DepartmentId?,
DrafterUserId, Phase (BudgetPhase 5-state), TongNganSach (sum auto
tu Details), SlaDeadline, SlaWarningSent.
- BudgetDetail — flat row pattern (GroupCode/GroupName + Item +
KhoiLuong/DonGia/ThanhTien). 18,4 precision KhoiLuong, 18,2 money.
- BudgetApproval — workflow history (FromPhase/ToPhase/Decision/Comment)
- BudgetChangelog — audit log unified (EntityType: Header/Detail/Workflow)
- BudgetPhase enum 5 state: DangSoanThao(1) → ChoCCM(2) → ChoCEO(3) →
DaDuyet(4) | TuChoi(99)
- BudgetPolicy hardcoded (no versioned WF, simple default per user
confirm 'tam thoi don gian'): Drafter/DeptManager → CCM → CEO/
AuthorizedSigner. Reject path back to DangSoanThao.
Migration 14 AddBudgets:
- 4 bang moi: Budgets + BudgetDetails + BudgetApprovals + BudgetChangelogs
- Index: Phase+IsDeleted, ProjectId, NamNganSach, SlaDeadline,
MaNganSach unique filtered. Cascade delete child.
- +2 cot FK ngoai bang (per user 'lien ket ca 3'):
* Contracts.BudgetId Guid? + index
* PurchaseEvaluations.BudgetId Guid? + index
Cho phep doi chieu chi phi HD/PE vs ngan sach goi thau.
Application CQRS (BudgetFeatures.cs ~340 line):
- CreateBudget + UpdateBudgetDraft + TransitionBudget + ListBudgets
(filter Phase/Project/Year + search + paging) + GetBudget bundle
(Header + Details + Approvals + Workflow summary)
- DeleteBudget (only DangSoanThao/TuChoi)
- AddBudgetDetail + UpdateBudgetDetail + DeleteBudgetDetail (auto
recompute TongNganSach = sum Details.ThanhTien)
- ListBudgetChangelogs
Api: BudgetsController 11 endpoint REST /api/budgets:
- GET / /{id} /{id}/changelogs
- POST / /{id}/transitions /{id}/details
- PUT /{id} /{id}/details/{detailId}
- DELETE /{id} /{id}/details/{detailId}
DbContext + IApplicationDbContext: 4 DbSet new (Budgets/Details/
Approvals/Changelogs).
MenuKeys + DbInitializer: 4 menu key (Budgets root + Bg_List/Create/
Pending leaves) seed dau order=27 'Ngan sach' icon Wallet. Auto-grant
admin permission via SeedAdminPermissionsAsync (MenuKeys.All).
MaNganSach format don gian 'NS-YYYYMM-NNNN' Random.Shared (chua atomic
sequence - user said 'tam thoi chua co').
Workflow chua versioned, hardcode BudgetPolicy.Default. Tuong lai admin
config qua UI: them BudgetWorkflowDefinition tables tuong tu PE.
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SolutionErp.Application.Common.Interfaces;
|
||||
using SolutionErp.Domain.Budgets;
|
||||
using SolutionErp.Domain.Contracts;
|
||||
using SolutionErp.Domain.Contracts.Details;
|
||||
using SolutionErp.Domain.Forms;
|
||||
@ -59,6 +60,12 @@ public class ApplicationDbContext
|
||||
public DbSet<PurchaseEvaluationWorkflowStepApprover> PurchaseEvaluationWorkflowStepApprovers => Set<PurchaseEvaluationWorkflowStepApprover>();
|
||||
public DbSet<PurchaseEvaluationCodeSequence> PurchaseEvaluationCodeSequences => Set<PurchaseEvaluationCodeSequence>();
|
||||
|
||||
// Module Ngân sách (Phase 7) — 4 bảng: Budget header + Details + Approvals + Changelogs.
|
||||
public DbSet<Budget> Budgets => Set<Budget>();
|
||||
public DbSet<BudgetDetail> BudgetDetails => Set<BudgetDetail>();
|
||||
public DbSet<BudgetApproval> BudgetApprovals => Set<BudgetApproval>();
|
||||
public DbSet<BudgetChangelog> BudgetChangelogs => Set<BudgetChangelog>();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
|
||||
@ -0,0 +1,89 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using SolutionErp.Domain.Budgets;
|
||||
|
||||
namespace SolutionErp.Infrastructure.Persistence.Configurations;
|
||||
|
||||
public class BudgetConfiguration : IEntityTypeConfiguration<Budget>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Budget> b)
|
||||
{
|
||||
b.ToTable("Budgets");
|
||||
b.HasKey(x => x.Id);
|
||||
|
||||
b.Property(x => x.MaNganSach).HasMaxLength(100);
|
||||
b.Property(x => x.TenNganSach).HasMaxLength(500).IsRequired();
|
||||
b.Property(x => x.Description).HasMaxLength(2000);
|
||||
b.Property(x => x.Phase).HasConversion<int>();
|
||||
b.Property(x => x.TongNganSach).HasPrecision(18, 2);
|
||||
|
||||
b.HasIndex(x => x.MaNganSach).IsUnique().HasFilter("[MaNganSach] IS NOT NULL");
|
||||
b.HasIndex(x => new { x.Phase, x.IsDeleted });
|
||||
b.HasIndex(x => x.ProjectId);
|
||||
b.HasIndex(x => x.NamNganSach);
|
||||
b.HasIndex(x => x.SlaDeadline);
|
||||
|
||||
b.HasMany(x => x.Details).WithOne(d => d.Budget).HasForeignKey(d => d.BudgetId).OnDelete(DeleteBehavior.Cascade);
|
||||
b.HasMany(x => x.Approvals).WithOne(a => a.Budget).HasForeignKey(a => a.BudgetId).OnDelete(DeleteBehavior.Cascade);
|
||||
b.HasMany(x => x.Changelogs).WithOne(c => c.Budget).HasForeignKey(c => c.BudgetId).OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasQueryFilter(x => !x.IsDeleted);
|
||||
}
|
||||
}
|
||||
|
||||
public class BudgetDetailConfiguration : IEntityTypeConfiguration<BudgetDetail>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<BudgetDetail> b)
|
||||
{
|
||||
b.ToTable("BudgetDetails");
|
||||
b.HasKey(x => x.Id);
|
||||
|
||||
b.Property(x => x.GroupCode).HasMaxLength(50).IsRequired();
|
||||
b.Property(x => x.GroupName).HasMaxLength(200).IsRequired();
|
||||
b.Property(x => x.ItemCode).HasMaxLength(100);
|
||||
b.Property(x => x.NoiDung).HasMaxLength(500).IsRequired();
|
||||
b.Property(x => x.DonViTinh).HasMaxLength(50);
|
||||
b.Property(x => x.GhiChu).HasMaxLength(1000);
|
||||
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.HasIndex(x => new { x.BudgetId, x.Order });
|
||||
}
|
||||
}
|
||||
|
||||
public class BudgetApprovalConfiguration : IEntityTypeConfiguration<BudgetApproval>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<BudgetApproval> b)
|
||||
{
|
||||
b.ToTable("BudgetApprovals");
|
||||
b.HasKey(x => x.Id);
|
||||
|
||||
b.Property(x => x.FromPhase).HasConversion<int>();
|
||||
b.Property(x => x.ToPhase).HasConversion<int>();
|
||||
b.Property(x => x.Decision).HasConversion<int>();
|
||||
b.Property(x => x.Comment).HasMaxLength(1000);
|
||||
|
||||
b.HasIndex(x => new { x.BudgetId, x.ApprovedAt });
|
||||
}
|
||||
}
|
||||
|
||||
public class BudgetChangelogConfiguration : IEntityTypeConfiguration<BudgetChangelog>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<BudgetChangelog> b)
|
||||
{
|
||||
b.ToTable("BudgetChangelogs");
|
||||
b.HasKey(x => x.Id);
|
||||
|
||||
b.Property(x => x.EntityType).HasConversion<int>();
|
||||
b.Property(x => x.Action).HasConversion<int>();
|
||||
b.Property(x => x.PhaseAtChange).HasConversion<int>();
|
||||
b.Property(x => x.UserName).HasMaxLength(200);
|
||||
b.Property(x => x.Summary).HasMaxLength(500);
|
||||
b.Property(x => x.ContextNote).HasMaxLength(2000);
|
||||
b.Property(x => x.FieldChangesJson).HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasIndex(x => new { x.BudgetId, x.CreatedAt });
|
||||
b.HasIndex(x => new { x.BudgetId, x.EntityType });
|
||||
}
|
||||
}
|
||||
@ -24,6 +24,7 @@ public class ContractConfiguration : IEntityTypeConfiguration<Contract>
|
||||
b.HasIndex(x => x.SupplierId);
|
||||
b.HasIndex(x => x.ProjectId);
|
||||
b.HasIndex(x => x.SlaDeadline);
|
||||
b.HasIndex(x => x.BudgetId);
|
||||
|
||||
b.HasMany(x => x.Approvals).WithOne(a => a.Contract).HasForeignKey(a => a.ContractId).OnDelete(DeleteBehavior.Cascade);
|
||||
b.HasMany(x => x.Comments).WithOne(c => c.Contract).HasForeignKey(c => c.ContractId).OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
@ -25,6 +25,7 @@ public class PurchaseEvaluationConfiguration : IEntityTypeConfiguration<Purchase
|
||||
b.HasIndex(x => x.SlaDeadline);
|
||||
b.HasIndex(x => x.WorkflowDefinitionId);
|
||||
b.HasIndex(x => x.ContractId);
|
||||
b.HasIndex(x => x.BudgetId);
|
||||
|
||||
b.HasMany(x => x.Suppliers).WithOne(s => s.PurchaseEvaluation).HasForeignKey(s => s.PurchaseEvaluationId).OnDelete(DeleteBehavior.Cascade);
|
||||
b.HasMany(x => x.Details).WithOne(d => d.PurchaseEvaluation).HasForeignKey(d => d.PurchaseEvaluationId).OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
@ -1308,6 +1308,11 @@ public static class DbInitializer
|
||||
// Module Duyệt NCC (tiền-HĐ)
|
||||
(MenuKeys.PurchaseEvaluations, "Quy trình chọn Thầu phụ - NCC", null, 25, "ClipboardCheck"),
|
||||
(MenuKeys.PeWorkflows, "Quy trình Duyệt NCC", MenuKeys.System, 95, "GitCompareArrows"),
|
||||
// Module Ngân sách (Phase 7)
|
||||
(MenuKeys.Budgets, "Ngân sách", null, 27, "Wallet"),
|
||||
(MenuKeys.BudgetList, "Danh sách", MenuKeys.Budgets, 1, "List"),
|
||||
(MenuKeys.BudgetCreate, "Thao tác", MenuKeys.Budgets, 2, "Plus"),
|
||||
(MenuKeys.BudgetPending, "Duyệt", MenuKeys.Budgets, 3, "CheckCircle2"),
|
||||
};
|
||||
|
||||
// Per-type sub-menu under Contracts: 1 group + 3 leaves each
|
||||
|
||||
3229
src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/20260428043508_AddBudgets.Designer.cs
generated
Normal file
3229
src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/20260428043508_AddBudgets.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,236 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace SolutionErp.Infrastructure.Persistence.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddBudgets : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "BudgetId",
|
||||
table: "PurchaseEvaluations",
|
||||
type: "uniqueidentifier",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "BudgetId",
|
||||
table: "Contracts",
|
||||
type: "uniqueidentifier",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Budgets",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
MaNganSach = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
TenNganSach = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
|
||||
NamNganSach = table.Column<int>(type: "int", nullable: false),
|
||||
ProjectId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
DepartmentId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DrafterUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
Phase = table.Column<int>(type: "int", nullable: false),
|
||||
TongNganSach = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
SlaDeadline = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
SlaWarningSent = table.Column<bool>(type: "bit", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false),
|
||||
DeletedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Budgets", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "BudgetApprovals",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
BudgetId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
FromPhase = table.Column<int>(type: "int", nullable: false),
|
||||
ToPhase = table.Column<int>(type: "int", nullable: false),
|
||||
ApproverUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
Decision = table.Column<int>(type: "int", nullable: false),
|
||||
Comment = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
|
||||
ApprovedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_BudgetApprovals", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_BudgetApprovals_Budgets_BudgetId",
|
||||
column: x => x.BudgetId,
|
||||
principalTable: "Budgets",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "BudgetChangelogs",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
BudgetId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
EntityType = table.Column<int>(type: "int", nullable: false),
|
||||
EntityId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
Action = table.Column<int>(type: "int", nullable: false),
|
||||
PhaseAtChange = table.Column<int>(type: "int", nullable: true),
|
||||
UserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
UserName = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
|
||||
Summary = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
FieldChangesJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
ContextNote = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_BudgetChangelogs", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_BudgetChangelogs_Budgets_BudgetId",
|
||||
column: x => x.BudgetId,
|
||||
principalTable: "Budgets",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "BudgetDetails",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
BudgetId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
GroupCode = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
GroupName = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
ItemCode = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
NoiDung = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
|
||||
DonViTinh = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
|
||||
KhoiLuong = table.Column<decimal>(type: "decimal(18,4)", precision: 18, scale: 4, nullable: false),
|
||||
DonGia = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
ThanhTien = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
Order = table.Column<int>(type: "int", nullable: false),
|
||||
GhiChu = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_BudgetDetails", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_BudgetDetails_Budgets_BudgetId",
|
||||
column: x => x.BudgetId,
|
||||
principalTable: "Budgets",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PurchaseEvaluations_BudgetId",
|
||||
table: "PurchaseEvaluations",
|
||||
column: "BudgetId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Contracts_BudgetId",
|
||||
table: "Contracts",
|
||||
column: "BudgetId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BudgetApprovals_BudgetId_ApprovedAt",
|
||||
table: "BudgetApprovals",
|
||||
columns: new[] { "BudgetId", "ApprovedAt" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BudgetChangelogs_BudgetId_CreatedAt",
|
||||
table: "BudgetChangelogs",
|
||||
columns: new[] { "BudgetId", "CreatedAt" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BudgetChangelogs_BudgetId_EntityType",
|
||||
table: "BudgetChangelogs",
|
||||
columns: new[] { "BudgetId", "EntityType" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BudgetDetails_BudgetId_Order",
|
||||
table: "BudgetDetails",
|
||||
columns: new[] { "BudgetId", "Order" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Budgets_MaNganSach",
|
||||
table: "Budgets",
|
||||
column: "MaNganSach",
|
||||
unique: true,
|
||||
filter: "[MaNganSach] IS NOT NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Budgets_NamNganSach",
|
||||
table: "Budgets",
|
||||
column: "NamNganSach");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Budgets_Phase_IsDeleted",
|
||||
table: "Budgets",
|
||||
columns: new[] { "Phase", "IsDeleted" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Budgets_ProjectId",
|
||||
table: "Budgets",
|
||||
column: "ProjectId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Budgets_SlaDeadline",
|
||||
table: "Budgets",
|
||||
column: "SlaDeadline");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "BudgetApprovals");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "BudgetChangelogs");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "BudgetDetails");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Budgets");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_PurchaseEvaluations_BudgetId",
|
||||
table: "PurchaseEvaluations");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Contracts_BudgetId",
|
||||
table: "Contracts");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "BudgetId",
|
||||
table: "PurchaseEvaluations");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "BudgetId",
|
||||
table: "Contracts");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,12 +125,274 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
|
||||
b.ToTable("UserTokens", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.Budgets.Budget", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("DepartmentId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("nvarchar(2000)");
|
||||
|
||||
b.Property<Guid?>("DrafterUserId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("MaNganSach")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int>("NamNganSach")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Phase")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<Guid>("ProjectId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime?>("SlaDeadline")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("SlaWarningSent")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("TenNganSach")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<decimal>("TongNganSach")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MaNganSach")
|
||||
.IsUnique()
|
||||
.HasFilter("[MaNganSach] IS NOT NULL");
|
||||
|
||||
b.HasIndex("NamNganSach");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.HasIndex("SlaDeadline");
|
||||
|
||||
b.HasIndex("Phase", "IsDeleted");
|
||||
|
||||
b.ToTable("Budgets", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.Budgets.BudgetApproval", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("ApprovedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("ApproverUserId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("BudgetId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Comment")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("nvarchar(1000)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<int>("Decision")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("FromPhase")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ToPhase")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BudgetId", "ApprovedAt");
|
||||
|
||||
b.ToTable("BudgetApprovals", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.Budgets.BudgetChangelog", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<int>("Action")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<Guid>("BudgetId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("ContextNote")
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("nvarchar(2000)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("EntityId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<int>("EntityType")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("FieldChangesJson")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int?>("PhaseAtChange")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Summary")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BudgetId", "CreatedAt");
|
||||
|
||||
b.HasIndex("BudgetId", "EntityType");
|
||||
|
||||
b.ToTable("BudgetChangelogs", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.Budgets.BudgetDetail", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("BudgetId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<decimal>("DonGia")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<string>("DonViTinh")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("GhiChu")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("nvarchar(1000)");
|
||||
|
||||
b.Property<string>("GroupCode")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("GroupName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("ItemCode")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<decimal>("KhoiLuong")
|
||||
.HasPrecision(18, 4)
|
||||
.HasColumnType("decimal(18,4)");
|
||||
|
||||
b.Property<string>("NoiDung")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("Order")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("ThanhTien")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BudgetId", "Order");
|
||||
|
||||
b.ToTable("BudgetDetails", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.Contracts.Contract", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("BudgetId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<bool>("BypassProcurementAndCCM")
|
||||
.HasColumnType("bit");
|
||||
|
||||
@ -206,6 +468,8 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BudgetId");
|
||||
|
||||
b.HasIndex("MaHopDong")
|
||||
.IsUnique()
|
||||
.HasFilter("[MaHopDong] IS NOT NULL");
|
||||
@ -1910,6 +2174,9 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("BudgetId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("ContractId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
@ -1983,6 +2250,8 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BudgetId");
|
||||
|
||||
b.HasIndex("ContractId");
|
||||
|
||||
b.HasIndex("MaPhieu")
|
||||
@ -2558,6 +2827,39 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.Budgets.BudgetApproval", b =>
|
||||
{
|
||||
b.HasOne("SolutionErp.Domain.Budgets.Budget", "Budget")
|
||||
.WithMany("Approvals")
|
||||
.HasForeignKey("BudgetId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Budget");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.Budgets.BudgetChangelog", b =>
|
||||
{
|
||||
b.HasOne("SolutionErp.Domain.Budgets.Budget", "Budget")
|
||||
.WithMany("Changelogs")
|
||||
.HasForeignKey("BudgetId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Budget");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.Budgets.BudgetDetail", b =>
|
||||
{
|
||||
b.HasOne("SolutionErp.Domain.Budgets.Budget", "Budget")
|
||||
.WithMany("Details")
|
||||
.HasForeignKey("BudgetId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Budget");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.Contracts.ContractApproval", b =>
|
||||
{
|
||||
b.HasOne("SolutionErp.Domain.Contracts.Contract", "Contract")
|
||||
@ -2838,6 +3140,15 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
|
||||
b.Navigation("Step");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.Budgets.Budget", b =>
|
||||
{
|
||||
b.Navigation("Approvals");
|
||||
|
||||
b.Navigation("Changelogs");
|
||||
|
||||
b.Navigation("Details");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SolutionErp.Domain.Contracts.Contract", b =>
|
||||
{
|
||||
b.Navigation("Approvals");
|
||||
|
||||
Reference in New Issue
Block a user