From adef288429d63419e9aa472375cdf7aed0b83ec5 Mon Sep 17 00:00:00 2001
From: 18631081161 <2088094923@qq.com>
Date: Wed, 14 Jan 2026 22:37:40 +0800
Subject: [PATCH] =?UTF-8?q?=E9=85=8D=E9=A2=9D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Controllers/AllocationsController.cs | 2 +-
.../MaterialCategoriesController.cs | 142 ++++
.../Data/ApplicationDbContext.cs | 10 +
...0114141545_AddMaterialCategory.Designer.cs | 672 ++++++++++++++++++
.../20260114141545_AddMaterialCategory.cs | 456 ++++++++++++
.../ApplicationDbContextModelSnapshot.cs | 669 +++++++++++++++++
.../Models/DTOs/MaterialCategoryDTOs.cs | 35 +
.../Models/Entities/MaterialCategory.cs | 34 +
src/MilitaryTrainingManagement/Program.cs | 67 ++
.../Implementations/AllocationService.cs | 8 +-
src/frontend/src/api/index.ts | 1 +
src/frontend/src/api/materialCategories.ts | 51 ++
src/frontend/src/router/index.ts | 6 +
.../src/views/allocations/AllocationForm.vue | 27 +-
.../src/views/allocations/AllocationList.vue | 6 +-
.../MaterialCategoryManagement.vue | 191 +++++
16 files changed, 2369 insertions(+), 8 deletions(-)
create mode 100644 src/MilitaryTrainingManagement/Controllers/MaterialCategoriesController.cs
create mode 100644 src/MilitaryTrainingManagement/Migrations/20260114141545_AddMaterialCategory.Designer.cs
create mode 100644 src/MilitaryTrainingManagement/Migrations/20260114141545_AddMaterialCategory.cs
create mode 100644 src/MilitaryTrainingManagement/Migrations/ApplicationDbContextModelSnapshot.cs
create mode 100644 src/MilitaryTrainingManagement/Models/DTOs/MaterialCategoryDTOs.cs
create mode 100644 src/MilitaryTrainingManagement/Models/Entities/MaterialCategory.cs
create mode 100644 src/frontend/src/api/materialCategories.ts
create mode 100644 src/frontend/src/views/allocations/MaterialCategoryManagement.vue
diff --git a/src/MilitaryTrainingManagement/Controllers/AllocationsController.cs b/src/MilitaryTrainingManagement/Controllers/AllocationsController.cs
index 9044ea1..cbf3ea3 100644
--- a/src/MilitaryTrainingManagement/Controllers/AllocationsController.cs
+++ b/src/MilitaryTrainingManagement/Controllers/AllocationsController.cs
@@ -280,7 +280,7 @@ public class AllocationsController : BaseApiController
quotaValid = isValid,
targetUnitsExist = targetUnitsExist,
isValid = isValid && targetUnitsExist,
- message = !isValid ? "分配配额总和超过总配额指标" :
+ message = !isValid ? "有配额未分配,无法提交" :
!targetUnitsExist ? "目标单位不存在" : "验证通过"
});
}
diff --git a/src/MilitaryTrainingManagement/Controllers/MaterialCategoriesController.cs b/src/MilitaryTrainingManagement/Controllers/MaterialCategoriesController.cs
new file mode 100644
index 0000000..fc47ffe
--- /dev/null
+++ b/src/MilitaryTrainingManagement/Controllers/MaterialCategoriesController.cs
@@ -0,0 +1,142 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using MilitaryTrainingManagement.Data;
+using MilitaryTrainingManagement.Models.DTOs;
+using MilitaryTrainingManagement.Models.Entities;
+
+namespace MilitaryTrainingManagement.Controllers;
+
+///
+/// 物资类别管理控制器
+///
+[Authorize]
+public class MaterialCategoriesController : BaseApiController
+{
+ private readonly ApplicationDbContext _context;
+
+ public MaterialCategoriesController(ApplicationDbContext context)
+ {
+ _context = context;
+ }
+
+ ///
+ /// 获取所有物资类别
+ ///
+ [HttpGet]
+ public async Task GetAll([FromQuery] bool? activeOnly = true)
+ {
+ var query = _context.MaterialCategories.AsQueryable();
+
+ if (activeOnly == true)
+ {
+ query = query.Where(c => c.IsActive);
+ }
+
+ var categories = await query
+ .OrderBy(c => c.SortOrder)
+ .ThenBy(c => c.Name)
+ .ToListAsync();
+
+ return Ok(categories);
+ }
+
+ ///
+ /// 根据ID获取物资类别
+ ///
+ [HttpGet("{id}")]
+ public async Task GetById(int id)
+ {
+ var category = await _context.MaterialCategories.FindAsync(id);
+ if (category == null)
+ {
+ return NotFound(new { message = "物资类别不存在" });
+ }
+ return Ok(category);
+ }
+
+ ///
+ /// 创建物资类别
+ ///
+ [HttpPost]
+ public async Task Create([FromBody] CreateMaterialCategoryRequest request)
+ {
+ // 检查名称是否已存在
+ var exists = await _context.MaterialCategories
+ .AnyAsync(c => c.Name == request.Name);
+ if (exists)
+ {
+ return BadRequest(new { message = "物资类别名称已存在" });
+ }
+
+ var category = new MaterialCategory
+ {
+ Name = request.Name,
+ Description = request.Description,
+ SortOrder = request.SortOrder,
+ IsActive = true,
+ CreatedAt = DateTime.UtcNow
+ };
+
+ _context.MaterialCategories.Add(category);
+ await _context.SaveChangesAsync();
+
+ return CreatedAtAction(nameof(GetById), new { id = category.Id }, category);
+ }
+
+ ///
+ /// 更新物资类别
+ ///
+ [HttpPut("{id}")]
+ public async Task Update(int id, [FromBody] UpdateMaterialCategoryRequest request)
+ {
+ var category = await _context.MaterialCategories.FindAsync(id);
+ if (category == null)
+ {
+ return NotFound(new { message = "物资类别不存在" });
+ }
+
+ // 检查名称是否与其他类别重复
+ var exists = await _context.MaterialCategories
+ .AnyAsync(c => c.Name == request.Name && c.Id != id);
+ if (exists)
+ {
+ return BadRequest(new { message = "物资类别名称已存在" });
+ }
+
+ category.Name = request.Name;
+ category.Description = request.Description;
+ category.SortOrder = request.SortOrder;
+ category.IsActive = request.IsActive;
+
+ await _context.SaveChangesAsync();
+
+ return Ok(category);
+ }
+
+ ///
+ /// 删除物资类别
+ ///
+ [HttpDelete("{id}")]
+ public async Task Delete(int id)
+ {
+ var category = await _context.MaterialCategories.FindAsync(id);
+ if (category == null)
+ {
+ return NotFound(new { message = "物资类别不存在" });
+ }
+
+ // 检查是否有配额使用此类别
+ var hasAllocations = await _context.MaterialAllocations
+ .AnyAsync(a => a.Category == category.Name);
+ if (hasAllocations)
+ {
+ return BadRequest(new { message = "该类别已被使用,无法删除" });
+ }
+
+ _context.MaterialCategories.Remove(category);
+ await _context.SaveChangesAsync();
+
+ return Ok(new { message = "删除成功" });
+ }
+}
diff --git a/src/MilitaryTrainingManagement/Data/ApplicationDbContext.cs b/src/MilitaryTrainingManagement/Data/ApplicationDbContext.cs
index e9478c2..2a6618e 100644
--- a/src/MilitaryTrainingManagement/Data/ApplicationDbContext.cs
+++ b/src/MilitaryTrainingManagement/Data/ApplicationDbContext.cs
@@ -17,6 +17,7 @@ public class ApplicationDbContext : DbContext
public DbSet UserAccounts => Set();
public DbSet MaterialAllocations => Set();
public DbSet AllocationDistributions => Set();
+ public DbSet MaterialCategories => Set();
public DbSet Personnel => Set();
public DbSet PersonnelApprovalHistories => Set();
public DbSet ApprovalRequests => Set();
@@ -65,6 +66,15 @@ public class ApplicationDbContext : DbContext
.OnDelete(DeleteBehavior.Restrict);
});
+ // MaterialCategory 配置
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasKey(e => e.Id);
+ entity.Property(e => e.Name).IsRequired().HasMaxLength(50);
+ entity.HasIndex(e => e.Name).IsUnique();
+ entity.Property(e => e.Description).HasMaxLength(200);
+ });
+
// AllocationDistribution 配置
modelBuilder.Entity(entity =>
{
diff --git a/src/MilitaryTrainingManagement/Migrations/20260114141545_AddMaterialCategory.Designer.cs b/src/MilitaryTrainingManagement/Migrations/20260114141545_AddMaterialCategory.Designer.cs
new file mode 100644
index 0000000..b89fc4f
--- /dev/null
+++ b/src/MilitaryTrainingManagement/Migrations/20260114141545_AddMaterialCategory.Designer.cs
@@ -0,0 +1,672 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using MilitaryTrainingManagement.Data;
+
+#nullable disable
+
+namespace MilitaryTrainingManagement.Migrations
+{
+ [DbContext(typeof(ApplicationDbContext))]
+ [Migration("20260114141545_AddMaterialCategory")]
+ partial class AddMaterialCategory
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.AllocationDistribution", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ActualCompletion")
+ .HasPrecision(18, 2)
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("AllocationId")
+ .HasColumnType("int");
+
+ b.Property("ApprovedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("ApprovedByUserId")
+ .HasColumnType("int");
+
+ b.Property("IsApproved")
+ .HasColumnType("bit");
+
+ b.Property("ReportedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("ReportedByUserId")
+ .HasColumnType("int");
+
+ b.Property("TargetUnitId")
+ .HasColumnType("int");
+
+ b.Property("UnitQuota")
+ .HasPrecision(18, 2)
+ .HasColumnType("decimal(18,2)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AllocationId");
+
+ b.HasIndex("ApprovedByUserId");
+
+ b.HasIndex("ReportedByUserId");
+
+ b.HasIndex("TargetUnitId");
+
+ b.ToTable("AllocationDistributions");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.ApprovalRequest", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("OriginalData")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Reason")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("RequestedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("RequestedByUnitId")
+ .HasColumnType("int");
+
+ b.Property("RequestedByUserId")
+ .HasColumnType("int");
+
+ b.Property("RequestedChanges")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ReviewComments")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ReviewedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("ReviewedByUserId")
+ .HasColumnType("int");
+
+ b.Property("Status")
+ .HasColumnType("int");
+
+ b.Property("TargetEntityId")
+ .HasColumnType("int");
+
+ b.Property("Type")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RequestedByUnitId");
+
+ b.HasIndex("RequestedByUserId");
+
+ b.HasIndex("ReviewedByUserId");
+
+ b.ToTable("ApprovalRequests");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.AuditLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Action")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("ChangedFields")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Description")
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("EntityId")
+ .HasColumnType("int");
+
+ b.Property("EntityType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("ErrorMessage")
+ .HasMaxLength(2000)
+ .HasColumnType("nvarchar(2000)");
+
+ b.Property("IpAddress")
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("IsSuccess")
+ .HasColumnType("bit");
+
+ b.Property("NewValues")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("OldValues")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("OrganizationalUnitId")
+ .HasColumnType("int");
+
+ b.Property("RequestPath")
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("Timestamp")
+ .HasColumnType("datetime2");
+
+ b.Property("UserAgent")
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Action");
+
+ b.HasIndex("EntityId");
+
+ b.HasIndex("EntityType");
+
+ b.HasIndex("OrganizationalUnitId");
+
+ b.HasIndex("Timestamp");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AuditLogs");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.MaterialAllocation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Category")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("CreatedByUnitId")
+ .HasColumnType("int");
+
+ b.Property("MaterialName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("nvarchar(200)");
+
+ b.Property("TotalQuota")
+ .HasPrecision(18, 2)
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("Unit")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatedByUnitId");
+
+ b.ToTable("MaterialAllocations");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.MaterialCategory", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("Description")
+ .HasMaxLength(200)
+ .HasColumnType("nvarchar(200)");
+
+ b.Property("IsActive")
+ .HasColumnType("bit");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("SortOrder")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.ToTable("MaterialCategories");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("Level")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("ParentId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ParentId");
+
+ b.ToTable("OrganizationalUnits");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.Personnel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Achievements")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Age")
+ .HasColumnType("int");
+
+ b.Property("ApprovedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("ApprovedByUnitId")
+ .HasColumnType("int");
+
+ b.Property("ApprovedLevel")
+ .HasColumnType("int");
+
+ b.Property("ContactInfo")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("EducationLevel")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Gender")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("nvarchar(10)");
+
+ b.Property("Height")
+ .HasPrecision(5, 2)
+ .HasColumnType("decimal(5,2)");
+
+ b.Property("Hometown")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("IdNumber")
+ .IsRequired()
+ .HasMaxLength(18)
+ .HasColumnType("nvarchar(18)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("PhotoPath")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Position")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("ProfessionalTitle")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Rank")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("Status")
+ .HasColumnType("int");
+
+ b.Property("SubmittedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("SubmittedByUnitId")
+ .HasColumnType("int");
+
+ b.Property("SupportingDocuments")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("TrainingParticipation")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ApprovedByUnitId");
+
+ b.HasIndex("IdNumber")
+ .IsUnique();
+
+ b.HasIndex("SubmittedByUnitId");
+
+ b.ToTable("Personnel");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.PersonnelApprovalHistory", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Action")
+ .HasColumnType("int");
+
+ b.Property("Comments")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("NewLevel")
+ .HasColumnType("int");
+
+ b.Property("NewStatus")
+ .HasColumnType("int");
+
+ b.Property("PersonnelId")
+ .HasColumnType("int");
+
+ b.Property("PreviousLevel")
+ .HasColumnType("int");
+
+ b.Property("PreviousStatus")
+ .HasColumnType("int");
+
+ b.Property("ReviewedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("ReviewedByUnitId")
+ .HasColumnType("int");
+
+ b.Property("ReviewedByUserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PersonnelId");
+
+ b.HasIndex("ReviewedByUnitId");
+
+ b.HasIndex("ReviewedByUserId");
+
+ b.ToTable("PersonnelApprovalHistories");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.UserAccount", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("IsActive")
+ .HasColumnType("bit");
+
+ b.Property("LastLoginAt")
+ .HasColumnType("datetime2");
+
+ b.Property("OrganizationalUnitId")
+ .HasColumnType("int");
+
+ b.Property("PasswordHash")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationalUnitId");
+
+ b.HasIndex("Username")
+ .IsUnique();
+
+ b.ToTable("UserAccounts");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.AllocationDistribution", b =>
+ {
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.MaterialAllocation", "Allocation")
+ .WithMany("Distributions")
+ .HasForeignKey("AllocationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ApprovedByUser")
+ .WithMany()
+ .HasForeignKey("ApprovedByUserId")
+ .OnDelete(DeleteBehavior.NoAction);
+
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ReportedByUser")
+ .WithMany()
+ .HasForeignKey("ReportedByUserId")
+ .OnDelete(DeleteBehavior.NoAction);
+
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "TargetUnit")
+ .WithMany()
+ .HasForeignKey("TargetUnitId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.Navigation("Allocation");
+
+ b.Navigation("ApprovedByUser");
+
+ b.Navigation("ReportedByUser");
+
+ b.Navigation("TargetUnit");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.ApprovalRequest", b =>
+ {
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "RequestedByUnit")
+ .WithMany()
+ .HasForeignKey("RequestedByUnitId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "RequestedByUser")
+ .WithMany()
+ .HasForeignKey("RequestedByUserId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ReviewedByUser")
+ .WithMany()
+ .HasForeignKey("ReviewedByUserId")
+ .OnDelete(DeleteBehavior.NoAction);
+
+ b.Navigation("RequestedByUnit");
+
+ b.Navigation("RequestedByUser");
+
+ b.Navigation("ReviewedByUser");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.AuditLog", b =>
+ {
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "OrganizationalUnit")
+ .WithMany()
+ .HasForeignKey("OrganizationalUnitId")
+ .OnDelete(DeleteBehavior.NoAction);
+
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.NoAction);
+
+ b.Navigation("OrganizationalUnit");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.MaterialAllocation", b =>
+ {
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "CreatedByUnit")
+ .WithMany()
+ .HasForeignKey("CreatedByUnitId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("CreatedByUnit");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", b =>
+ {
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "Parent")
+ .WithMany("Children")
+ .HasForeignKey("ParentId")
+ .OnDelete(DeleteBehavior.Restrict);
+
+ b.Navigation("Parent");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.Personnel", b =>
+ {
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "ApprovedByUnit")
+ .WithMany()
+ .HasForeignKey("ApprovedByUnitId")
+ .OnDelete(DeleteBehavior.NoAction);
+
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "SubmittedByUnit")
+ .WithMany()
+ .HasForeignKey("SubmittedByUnitId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.Navigation("ApprovedByUnit");
+
+ b.Navigation("SubmittedByUnit");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.PersonnelApprovalHistory", b =>
+ {
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.Personnel", "Personnel")
+ .WithMany()
+ .HasForeignKey("PersonnelId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "ReviewedByUnit")
+ .WithMany()
+ .HasForeignKey("ReviewedByUnitId")
+ .OnDelete(DeleteBehavior.NoAction);
+
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ReviewedByUser")
+ .WithMany()
+ .HasForeignKey("ReviewedByUserId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.Navigation("Personnel");
+
+ b.Navigation("ReviewedByUnit");
+
+ b.Navigation("ReviewedByUser");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.UserAccount", b =>
+ {
+ b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "OrganizationalUnit")
+ .WithMany("Accounts")
+ .HasForeignKey("OrganizationalUnitId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("OrganizationalUnit");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.MaterialAllocation", b =>
+ {
+ b.Navigation("Distributions");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", b =>
+ {
+ b.Navigation("Accounts");
+
+ b.Navigation("Children");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/MilitaryTrainingManagement/Migrations/20260114141545_AddMaterialCategory.cs b/src/MilitaryTrainingManagement/Migrations/20260114141545_AddMaterialCategory.cs
new file mode 100644
index 0000000..b3a0af0
--- /dev/null
+++ b/src/MilitaryTrainingManagement/Migrations/20260114141545_AddMaterialCategory.cs
@@ -0,0 +1,456 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace MilitaryTrainingManagement.Migrations
+{
+ ///
+ public partial class AddMaterialCategory : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "MaterialCategories",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false),
+ Description = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true),
+ IsActive = table.Column(type: "bit", nullable: false),
+ CreatedAt = table.Column(type: "datetime2", nullable: false),
+ SortOrder = table.Column(type: "int", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_MaterialCategories", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "OrganizationalUnits",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ Name = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false),
+ Level = table.Column(type: "int", nullable: false),
+ ParentId = table.Column(type: "int", nullable: true),
+ CreatedAt = table.Column(type: "datetime2", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_OrganizationalUnits", x => x.Id);
+ table.ForeignKey(
+ name: "FK_OrganizationalUnits_OrganizationalUnits_ParentId",
+ column: x => x.ParentId,
+ principalTable: "OrganizationalUnits",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "MaterialAllocations",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ Category = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false),
+ MaterialName = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false),
+ Unit = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false),
+ TotalQuota = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
+ CreatedByUnitId = table.Column(type: "int", nullable: false),
+ CreatedAt = table.Column(type: "datetime2", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_MaterialAllocations", x => x.Id);
+ table.ForeignKey(
+ name: "FK_MaterialAllocations_OrganizationalUnits_CreatedByUnitId",
+ column: x => x.CreatedByUnitId,
+ principalTable: "OrganizationalUnits",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Personnel",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false),
+ PhotoPath = table.Column(type: "nvarchar(max)", nullable: true),
+ Position = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false),
+ Rank = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false),
+ Gender = table.Column(type: "nvarchar(10)", maxLength: 10, nullable: false),
+ IdNumber = table.Column(type: "nvarchar(18)", maxLength: 18, nullable: false),
+ ProfessionalTitle = table.Column(type: "nvarchar(max)", nullable: true),
+ EducationLevel = table.Column(type: "nvarchar(max)", nullable: true),
+ Age = table.Column(type: "int", nullable: false),
+ Height = table.Column(type: "decimal(5,2)", precision: 5, scale: 2, nullable: true),
+ ContactInfo = table.Column(type: "nvarchar(max)", nullable: true),
+ Hometown = table.Column(type: "nvarchar(max)", nullable: true),
+ TrainingParticipation = table.Column(type: "nvarchar(max)", nullable: true),
+ Achievements = table.Column(type: "nvarchar(max)", nullable: true),
+ SupportingDocuments = table.Column(type: "nvarchar(max)", nullable: true),
+ SubmittedByUnitId = table.Column(type: "int", nullable: false),
+ ApprovedLevel = table.Column(type: "int", nullable: true),
+ ApprovedByUnitId = table.Column(type: "int", nullable: true),
+ Status = table.Column(type: "int", nullable: false),
+ SubmittedAt = table.Column(type: "datetime2", nullable: false),
+ ApprovedAt = table.Column(type: "datetime2", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Personnel", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Personnel_OrganizationalUnits_ApprovedByUnitId",
+ column: x => x.ApprovedByUnitId,
+ principalTable: "OrganizationalUnits",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_Personnel_OrganizationalUnits_SubmittedByUnitId",
+ column: x => x.SubmittedByUnitId,
+ principalTable: "OrganizationalUnits",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateTable(
+ name: "UserAccounts",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ Username = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false),
+ PasswordHash = table.Column(type: "nvarchar(max)", nullable: false),
+ DisplayName = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false),
+ OrganizationalUnitId = table.Column(type: "int", nullable: false),
+ IsActive = table.Column(type: "bit", nullable: false),
+ CreatedAt = table.Column(type: "datetime2", nullable: false),
+ LastLoginAt = table.Column(type: "datetime2", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_UserAccounts", x => x.Id);
+ table.ForeignKey(
+ name: "FK_UserAccounts_OrganizationalUnits_OrganizationalUnitId",
+ column: x => x.OrganizationalUnitId,
+ principalTable: "OrganizationalUnits",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AllocationDistributions",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ AllocationId = table.Column(type: "int", nullable: false),
+ TargetUnitId = table.Column(type: "int", nullable: false),
+ UnitQuota = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
+ ActualCompletion = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true),
+ ReportedAt = table.Column(type: "datetime2", nullable: true),
+ ReportedByUserId = table.Column(type: "int", nullable: true),
+ IsApproved = table.Column(type: "bit", nullable: false),
+ ApprovedAt = table.Column(type: "datetime2", nullable: true),
+ ApprovedByUserId = table.Column(type: "int", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AllocationDistributions", x => x.Id);
+ table.ForeignKey(
+ name: "FK_AllocationDistributions_MaterialAllocations_AllocationId",
+ column: x => x.AllocationId,
+ principalTable: "MaterialAllocations",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_AllocationDistributions_OrganizationalUnits_TargetUnitId",
+ column: x => x.TargetUnitId,
+ principalTable: "OrganizationalUnits",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_AllocationDistributions_UserAccounts_ApprovedByUserId",
+ column: x => x.ApprovedByUserId,
+ principalTable: "UserAccounts",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_AllocationDistributions_UserAccounts_ReportedByUserId",
+ column: x => x.ReportedByUserId,
+ principalTable: "UserAccounts",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateTable(
+ name: "ApprovalRequests",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ Type = table.Column(type: "int", nullable: false),
+ TargetEntityId = table.Column(type: "int", nullable: false),
+ RequestedByUserId = table.Column(type: "int", nullable: false),
+ RequestedByUnitId = table.Column(type: "int", nullable: false),
+ Reason = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: false),
+ OriginalData = table.Column(type: "nvarchar(max)", nullable: false),
+ RequestedChanges = table.Column(type: "nvarchar(max)", nullable: false),
+ Status = table.Column(type: "int", nullable: false),
+ ReviewedByUserId = table.Column(type: "int", nullable: true),
+ ReviewComments = table.Column(type: "nvarchar(max)", nullable: true),
+ RequestedAt = table.Column(type: "datetime2", nullable: false),
+ ReviewedAt = table.Column(type: "datetime2", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_ApprovalRequests", x => x.Id);
+ table.ForeignKey(
+ name: "FK_ApprovalRequests_OrganizationalUnits_RequestedByUnitId",
+ column: x => x.RequestedByUnitId,
+ principalTable: "OrganizationalUnits",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_ApprovalRequests_UserAccounts_RequestedByUserId",
+ column: x => x.RequestedByUserId,
+ principalTable: "UserAccounts",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_ApprovalRequests_UserAccounts_ReviewedByUserId",
+ column: x => x.ReviewedByUserId,
+ principalTable: "UserAccounts",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AuditLogs",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ EntityType = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false),
+ EntityId = table.Column(type: "int", nullable: false),
+ Action = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false),
+ Description = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true),
+ OldValues = table.Column(type: "nvarchar(max)", nullable: true),
+ NewValues = table.Column(type: "nvarchar(max)", nullable: true),
+ ChangedFields = table.Column(type: "nvarchar(max)", nullable: true),
+ UserId = table.Column(type: "int", nullable: true),
+ OrganizationalUnitId = table.Column(type: "int", nullable: true),
+ Timestamp = table.Column(type: "datetime2", nullable: false),
+ IpAddress = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true),
+ UserAgent = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true),
+ RequestPath = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true),
+ IsSuccess = table.Column(type: "bit", nullable: false),
+ ErrorMessage = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AuditLogs", x => x.Id);
+ table.ForeignKey(
+ name: "FK_AuditLogs_OrganizationalUnits_OrganizationalUnitId",
+ column: x => x.OrganizationalUnitId,
+ principalTable: "OrganizationalUnits",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_AuditLogs_UserAccounts_UserId",
+ column: x => x.UserId,
+ principalTable: "UserAccounts",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateTable(
+ name: "PersonnelApprovalHistories",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ PersonnelId = table.Column(type: "int", nullable: false),
+ Action = table.Column(type: "int", nullable: false),
+ PreviousStatus = table.Column(type: "int", nullable: true),
+ NewStatus = table.Column(type: "int", nullable: false),
+ PreviousLevel = table.Column(type: "int", nullable: true),
+ NewLevel = table.Column(type: "int", nullable: true),
+ ReviewedByUserId = table.Column(type: "int", nullable: false),
+ ReviewedByUnitId = table.Column(type: "int", nullable: true),
+ Comments = table.Column(type: "nvarchar(max)", nullable: true),
+ ReviewedAt = table.Column(type: "datetime2", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_PersonnelApprovalHistories", x => x.Id);
+ table.ForeignKey(
+ name: "FK_PersonnelApprovalHistories_OrganizationalUnits_ReviewedByUnitId",
+ column: x => x.ReviewedByUnitId,
+ principalTable: "OrganizationalUnits",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_PersonnelApprovalHistories_Personnel_PersonnelId",
+ column: x => x.PersonnelId,
+ principalTable: "Personnel",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_PersonnelApprovalHistories_UserAccounts_ReviewedByUserId",
+ column: x => x.ReviewedByUserId,
+ principalTable: "UserAccounts",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AllocationDistributions_AllocationId",
+ table: "AllocationDistributions",
+ column: "AllocationId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AllocationDistributions_ApprovedByUserId",
+ table: "AllocationDistributions",
+ column: "ApprovedByUserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AllocationDistributions_ReportedByUserId",
+ table: "AllocationDistributions",
+ column: "ReportedByUserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AllocationDistributions_TargetUnitId",
+ table: "AllocationDistributions",
+ column: "TargetUnitId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_ApprovalRequests_RequestedByUnitId",
+ table: "ApprovalRequests",
+ column: "RequestedByUnitId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_ApprovalRequests_RequestedByUserId",
+ table: "ApprovalRequests",
+ column: "RequestedByUserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_ApprovalRequests_ReviewedByUserId",
+ table: "ApprovalRequests",
+ column: "ReviewedByUserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AuditLogs_Action",
+ table: "AuditLogs",
+ column: "Action");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AuditLogs_EntityId",
+ table: "AuditLogs",
+ column: "EntityId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AuditLogs_EntityType",
+ table: "AuditLogs",
+ column: "EntityType");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AuditLogs_OrganizationalUnitId",
+ table: "AuditLogs",
+ column: "OrganizationalUnitId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AuditLogs_Timestamp",
+ table: "AuditLogs",
+ column: "Timestamp");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AuditLogs_UserId",
+ table: "AuditLogs",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_MaterialAllocations_CreatedByUnitId",
+ table: "MaterialAllocations",
+ column: "CreatedByUnitId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_MaterialCategories_Name",
+ table: "MaterialCategories",
+ column: "Name",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_OrganizationalUnits_ParentId",
+ table: "OrganizationalUnits",
+ column: "ParentId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Personnel_ApprovedByUnitId",
+ table: "Personnel",
+ column: "ApprovedByUnitId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Personnel_IdNumber",
+ table: "Personnel",
+ column: "IdNumber",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Personnel_SubmittedByUnitId",
+ table: "Personnel",
+ column: "SubmittedByUnitId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_PersonnelApprovalHistories_PersonnelId",
+ table: "PersonnelApprovalHistories",
+ column: "PersonnelId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_PersonnelApprovalHistories_ReviewedByUnitId",
+ table: "PersonnelApprovalHistories",
+ column: "ReviewedByUnitId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_PersonnelApprovalHistories_ReviewedByUserId",
+ table: "PersonnelApprovalHistories",
+ column: "ReviewedByUserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_UserAccounts_OrganizationalUnitId",
+ table: "UserAccounts",
+ column: "OrganizationalUnitId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_UserAccounts_Username",
+ table: "UserAccounts",
+ column: "Username",
+ unique: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "AllocationDistributions");
+
+ migrationBuilder.DropTable(
+ name: "ApprovalRequests");
+
+ migrationBuilder.DropTable(
+ name: "AuditLogs");
+
+ migrationBuilder.DropTable(
+ name: "MaterialCategories");
+
+ migrationBuilder.DropTable(
+ name: "PersonnelApprovalHistories");
+
+ migrationBuilder.DropTable(
+ name: "MaterialAllocations");
+
+ migrationBuilder.DropTable(
+ name: "Personnel");
+
+ migrationBuilder.DropTable(
+ name: "UserAccounts");
+
+ migrationBuilder.DropTable(
+ name: "OrganizationalUnits");
+ }
+ }
+}
diff --git a/src/MilitaryTrainingManagement/Migrations/ApplicationDbContextModelSnapshot.cs b/src/MilitaryTrainingManagement/Migrations/ApplicationDbContextModelSnapshot.cs
new file mode 100644
index 0000000..45a79ea
--- /dev/null
+++ b/src/MilitaryTrainingManagement/Migrations/ApplicationDbContextModelSnapshot.cs
@@ -0,0 +1,669 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using MilitaryTrainingManagement.Data;
+
+#nullable disable
+
+namespace MilitaryTrainingManagement.Migrations
+{
+ [DbContext(typeof(ApplicationDbContext))]
+ partial class ApplicationDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.AllocationDistribution", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ActualCompletion")
+ .HasPrecision(18, 2)
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("AllocationId")
+ .HasColumnType("int");
+
+ b.Property("ApprovedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("ApprovedByUserId")
+ .HasColumnType("int");
+
+ b.Property("IsApproved")
+ .HasColumnType("bit");
+
+ b.Property("ReportedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("ReportedByUserId")
+ .HasColumnType("int");
+
+ b.Property("TargetUnitId")
+ .HasColumnType("int");
+
+ b.Property("UnitQuota")
+ .HasPrecision(18, 2)
+ .HasColumnType("decimal(18,2)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AllocationId");
+
+ b.HasIndex("ApprovedByUserId");
+
+ b.HasIndex("ReportedByUserId");
+
+ b.HasIndex("TargetUnitId");
+
+ b.ToTable("AllocationDistributions");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.ApprovalRequest", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("OriginalData")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Reason")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("RequestedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("RequestedByUnitId")
+ .HasColumnType("int");
+
+ b.Property("RequestedByUserId")
+ .HasColumnType("int");
+
+ b.Property("RequestedChanges")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ReviewComments")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ReviewedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("ReviewedByUserId")
+ .HasColumnType("int");
+
+ b.Property("Status")
+ .HasColumnType("int");
+
+ b.Property("TargetEntityId")
+ .HasColumnType("int");
+
+ b.Property("Type")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RequestedByUnitId");
+
+ b.HasIndex("RequestedByUserId");
+
+ b.HasIndex("ReviewedByUserId");
+
+ b.ToTable("ApprovalRequests");
+ });
+
+ modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.AuditLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Action")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property