[CLAUDE] Domain+App+Infra+FE-Admin+FE-User: S34 Plan 4 G-H2 Mig 35 schema foundation
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m30s

Phase 10.2 G-H2 Cấu hình HRM — 4 catalog lookup foundation deploy (BE CRUD +
FE forms DEFER S35 cho clean handoff).

Mig 35 `AddHrmConfigs` — 4 table mới:
- LeaveTypes (Code unique + Name + DaysPerYear decimal(5,2) + IsPaid +
  RequiresAttachment) — 5 sample seed (ANNUAL 12d + SICK 30d + MATERNITY 180d
  + COMPASSIONATE 3d + UNPAID 0d)
- Holidays (Year + Date UNIQUE composite + Name + IsRecurring + IsPaid) —
  10 sample VN 2026 (Tết Dương + 5 Tết Nguyên đán placeholder + Giỗ tổ +
  30/4 + 1/5 + 2/9 + Quốc khánh)
- ShiftPatterns (Code unique + Name + StartTime/EndTime TimeOnly + BreakMinutes +
  WorkDays comma string) — 3 sample (HC 8-17 T2-T6 + CA1 6-14 T2-T7 + CA2 14-22)
- OtPolicies (Code unique + 3 Multiplier decimal(4,2) + 3 MaxHours int) —
  1 sample STANDARD (1.5x/2.0x/3.0x weekday/weekend/holiday + 4h/40h/200h cap
  Luật Lao động VN 2019)

Files:
- Domain/Hrm/{LeaveType,Holiday,ShiftPattern,OtPolicy}.cs (4 entity AuditableEntity)
- Infrastructure/Persistence/Configurations/{LeaveType,Holiday,ShiftPattern,OtPolicy}Configuration.cs (4 EF Config UNIQUE indexes)
- IApplicationDbContext + ApplicationDbContext +4 DbSet
- Migrations/20260527075940_AddHrmConfigs.{cs,Designer.cs} + Snapshot updated (3-file rule)
- DbInitializer.SeedHrmConfigsAsync ~120 LOC seed sample (NOT gated DemoSeed per gotcha #51)
- MenuKeys.cs +HrmConfig sub-group + 4 leaf (LeaveTypes/Holidays/Shifts/OtPolicies) Order=2 dưới Hrm
- DbInitializer.SeedMenuTreeAsync +5 entry (sub-group + 4 leaf)
- fe-admin + fe-user menuKeys.ts +5 const mirror BE (Pattern 16-bis sync)

Verify:
- dotnet build PASS (2 warn DocxRenderer baseline, 0 error)
- dotnet test 130/130 PASS baseline preserve
- Mig 35 applied LocalDB SolutionErp_Dev — verified via dotnet ef database update
- 4 catalog table created + 5+10+3+1 = 19 sample row seed

Defer S35:
- Task 2 BE CQRS 4 catalog CRUD (16 endpoint) — Implementer Case 2 cookie-cutter
- Task 4 FE 2 app 4 catalog page (list/create/edit dialog) — Implementer Case 2

Cumulative S34 mig: 34 → 35 (+1). Tables 67 → 71 (+4). Menu keys 64 → 69 (+5).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-27 15:04:10 +07:00
parent e506cd8135
commit 07b3f3b284
17 changed files with 5739 additions and 0 deletions

View File

@ -90,6 +90,12 @@ public class ApplicationDbContext
public DbSet<EmployeeDocument> EmployeeDocuments => Set<EmployeeDocument>();
public DbSet<EmployeeCodeSequence> EmployeeCodeSequences => Set<EmployeeCodeSequence>();
// Phase 10.2 G-H2 (Mig 35 — S34) — Cấu hình HRM 4 catalog lookup.
public DbSet<LeaveType> LeaveTypes => Set<LeaveType>();
public DbSet<Holiday> Holidays => Set<Holiday>();
public DbSet<ShiftPattern> ShiftPatterns => Set<ShiftPattern>();
public DbSet<OtPolicy> OtPolicies => Set<OtPolicy>();
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);

View File

@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using SolutionErp.Domain.Hrm;
namespace SolutionErp.Infrastructure.Persistence.Configurations;
// EF Mig 35 G-H2 (S34) — Ngày lễ. UNIQUE composite (Year, Date).
public class HolidayConfiguration : IEntityTypeConfiguration<Holiday>
{
public void Configure(EntityTypeBuilder<Holiday> e)
{
e.ToTable("Holidays");
e.Property(x => x.Name).HasMaxLength(200).IsRequired();
e.Property(x => x.Description).HasMaxLength(500);
e.HasIndex(x => new { x.Year, x.Date }).IsUnique();
}
}

View File

@ -0,0 +1,21 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using SolutionErp.Domain.Hrm;
namespace SolutionErp.Infrastructure.Persistence.Configurations;
// EF Mig 35 G-H2 (S34) — Loại phép. Catalog standalone, no FK.
public class LeaveTypeConfiguration : IEntityTypeConfiguration<LeaveType>
{
public void Configure(EntityTypeBuilder<LeaveType> e)
{
e.ToTable("LeaveTypes");
e.Property(x => x.Code).HasMaxLength(50).IsRequired();
e.Property(x => x.Name).HasMaxLength(200).IsRequired();
e.Property(x => x.DaysPerYear).HasColumnType("decimal(5,2)");
e.Property(x => x.Description).HasMaxLength(500);
e.HasIndex(x => x.Code).IsUnique();
}
}

View File

@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using SolutionErp.Domain.Hrm;
namespace SolutionErp.Infrastructure.Persistence.Configurations;
// EF Mig 35 G-H2 (S34) — Chính sách OT. Catalog standalone.
// Future business logic: G-P1 chấm công + G-O4 OtRequest reference IsActive=true.
public class OtPolicyConfiguration : IEntityTypeConfiguration<OtPolicy>
{
public void Configure(EntityTypeBuilder<OtPolicy> e)
{
e.ToTable("OtPolicies");
e.Property(x => x.Code).HasMaxLength(50).IsRequired();
e.Property(x => x.Name).HasMaxLength(200).IsRequired();
e.Property(x => x.MultiplierWeekday).HasColumnType("decimal(4,2)");
e.Property(x => x.MultiplierWeekend).HasColumnType("decimal(4,2)");
e.Property(x => x.MultiplierHoliday).HasColumnType("decimal(4,2)");
e.Property(x => x.Description).HasMaxLength(500);
e.HasIndex(x => x.Code).IsUnique();
}
}

View File

@ -0,0 +1,21 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using SolutionErp.Domain.Hrm;
namespace SolutionErp.Infrastructure.Persistence.Configurations;
// EF Mig 35 G-H2 (S34) — Ca làm việc. Catalog standalone.
public class ShiftPatternConfiguration : IEntityTypeConfiguration<ShiftPattern>
{
public void Configure(EntityTypeBuilder<ShiftPattern> e)
{
e.ToTable("ShiftPatterns");
e.Property(x => x.Code).HasMaxLength(20).IsRequired();
e.Property(x => x.Name).HasMaxLength(200).IsRequired();
e.Property(x => x.WorkDays).HasMaxLength(100).IsRequired(); // "Mon,Tue,Wed,Thu,Fri"
e.Property(x => x.Description).HasMaxLength(500);
e.HasIndex(x => x.Code).IsUnique();
}
}

View File

@ -92,6 +92,9 @@ public static class DbInitializer
// (infrastructure data, mirror Mig 32 SeedSampleContractWorkflowV2
// gotcha #51 lesson). Bro UAT update field nhạy cảm qua FE Hồ sơ NS.
await SeedDemoEmployeeProfilesAsync(db, userManager, logger);
// Plan G-H2 (Mig 35 S34 2026-05-27) — Cấu hình HRM 4 catalog. Infrastructure
// data (NOT gated DemoSeed flag) — Workflow Apps reference cần data ngày 1.
await SeedHrmConfigsAsync(db, logger);
await SeedMenuTreeAsync(db, logger);
await SeedAdminPermissionsAsync(db, roleManager, logger);
await SeedDemoMasterDataAsync(db, logger);
@ -1484,6 +1487,13 @@ public static class DbInitializer
(MenuKeys.Hrm, "Nhân sự", null, 28, "UserCircle"),
(MenuKeys.HrmHoSo, "Hồ sơ Nhân sự", MenuKeys.Hrm, 1, "ContactRound"),
// Phase 10.2 G-H2 (Mig 35 — S34). Sub-group "Cấu hình HRM" + 4 catalog leaf.
(MenuKeys.HrmConfig, "Cấu hình HRM", MenuKeys.Hrm, 2, "Settings2"),
(MenuKeys.HrmConfigLeaveTypes, "Loại phép", MenuKeys.HrmConfig, 1, "CalendarOff"),
(MenuKeys.HrmConfigHolidays, "Ngày lễ", MenuKeys.HrmConfig, 2, "PartyPopper"),
(MenuKeys.HrmConfigShifts, "Ca làm việc", MenuKeys.HrmConfig, 3, "Clock"),
(MenuKeys.HrmConfigOtPolicies, "Chính sách OT", MenuKeys.HrmConfig, 4, "TimerReset"),
// Module Văn phòng số (Phase 10.2 G-O1+ S34). 1 root + leaf Danh bạ.
// Future leaf: Off_PhongHop (G-O2) + workflow apps Off_DeXuat/DonTu/DatXe/ItTicket.
(MenuKeys.Off, "Văn phòng số", null, 29, "Briefcase"),
@ -2029,4 +2039,121 @@ public static class DbInitializer
"SeedDemoEmployeeProfilesAsync: seeded {Count} profiles + 1 sequence row NV/{Year} LastSeq={Seq}",
seq, year, seq);
}
// Phase 10.2 G-H2 (Mig 35 — S34 2026-05-27) — Cấu hình HRM 4 catalog seed sample.
// INFRASTRUCTURE seed (NOT gated DemoSeed flag — gotcha #51 lesson).
// Workflow Apps Phase 10.3 (G-O4 LeaveRequest, G-P1 chấm công OT) reference
// 4 catalog active rows ngày 1 → admin có thể tinh chỉnh sau qua Designer UI.
private static async Task SeedHrmConfigsAsync(ApplicationDbContext db, ILogger logger)
{
if (await db.LeaveTypes.AnyAsync()
&& await db.Holidays.AnyAsync()
&& await db.ShiftPatterns.AnyAsync()
&& await db.OtPolicies.AnyAsync())
{
logger.LogInformation("SeedHrmConfigsAsync: skip — đã có 4 catalog.");
return;
}
// 5 LeaveType — Luật Lao động VN 2019 reference.
if (!await db.LeaveTypes.AnyAsync())
{
db.LeaveTypes.AddRange(
new LeaveType
{
Code = "ANNUAL", Name = "Phép năm", DaysPerYear = 12m, IsPaid = true,
RequiresAttachment = false,
Description = "Phép năm tiêu chuẩn. Luật quy định tối thiểu 12 ngày/năm cho lao động làm việc đủ 12 tháng.",
},
new LeaveType
{
Code = "SICK", Name = "Phép ốm", DaysPerYear = 30m, IsPaid = true,
RequiresAttachment = true,
Description = "Nghỉ ốm có giấy bác sĩ. BHXH chi trả 75% lương.",
},
new LeaveType
{
Code = "MATERNITY", Name = "Phép thai sản", DaysPerYear = 180m, IsPaid = true,
RequiresAttachment = true,
Description = "Phép thai sản 6 tháng (180 ngày) cho lao động nữ. BHXH chi trả 100%.",
},
new LeaveType
{
Code = "COMPASSIONATE", Name = "Phép việc riêng", DaysPerYear = 3m, IsPaid = true,
RequiresAttachment = false,
Description = "Cưới hỏi / hiếu / việc gia đình quan trọng. Luật quy định 1-3 ngày tùy lý do.",
},
new LeaveType
{
Code = "UNPAID", Name = "Phép không lương", DaysPerYear = 0m, IsPaid = false,
RequiresAttachment = false,
Description = "Nghỉ không lương — không giới hạn, cần BOD duyệt.",
});
}
// 10 Holiday VN 2026 (placeholder Tết Nguyên đán date — admin update khi có lịch chính thức).
if (!await db.Holidays.AnyAsync())
{
db.Holidays.AddRange(
new Holiday { Year = 2026, Date = new DateOnly(2026, 1, 1), Name = "Tết Dương lịch", IsRecurring = true },
// Tết Nguyên đán 2026 (Bính Ngọ) — 17/2 mùng 1 Âm — 5 ngày 16-20/2
new Holiday { Year = 2026, Date = new DateOnly(2026, 2, 16), Name = "Tết Nguyên đán (30 Tết)", IsRecurring = false },
new Holiday { Year = 2026, Date = new DateOnly(2026, 2, 17), Name = "Tết Nguyên đán (Mùng 1)", IsRecurring = false },
new Holiday { Year = 2026, Date = new DateOnly(2026, 2, 18), Name = "Tết Nguyên đán (Mùng 2)", IsRecurring = false },
new Holiday { Year = 2026, Date = new DateOnly(2026, 2, 19), Name = "Tết Nguyên đán (Mùng 3)", IsRecurring = false },
new Holiday { Year = 2026, Date = new DateOnly(2026, 2, 20), Name = "Tết Nguyên đán (Mùng 4)", IsRecurring = false },
// Giỗ tổ Hùng Vương 10/3 Âm — 2026 placeholder 14/4
new Holiday { Year = 2026, Date = new DateOnly(2026, 4, 14), Name = "Giỗ tổ Hùng Vương", IsRecurring = false },
new Holiday { Year = 2026, Date = new DateOnly(2026, 4, 30), Name = "Giải phóng miền Nam", IsRecurring = true },
new Holiday { Year = 2026, Date = new DateOnly(2026, 5, 1), Name = "Quốc tế Lao động", IsRecurring = true },
new Holiday { Year = 2026, Date = new DateOnly(2026, 9, 2), Name = "Quốc khánh", IsRecurring = true });
}
// 3 ShiftPattern — hành chính + 2 ca xoay.
if (!await db.ShiftPatterns.AnyAsync())
{
db.ShiftPatterns.AddRange(
new ShiftPattern
{
Code = "HC", Name = "Hành chính",
StartTime = new TimeOnly(8, 0), EndTime = new TimeOnly(17, 0),
BreakMinutes = 60, WorkDays = "Mon,Tue,Wed,Thu,Fri",
Description = "Ca hành chính chuẩn 8-17h, nghỉ trưa 60 phút, T2-T6.",
},
new ShiftPattern
{
Code = "CA1", Name = "Ca sáng",
StartTime = new TimeOnly(6, 0), EndTime = new TimeOnly(14, 0),
BreakMinutes = 30, WorkDays = "Mon,Tue,Wed,Thu,Fri,Sat",
Description = "Ca sáng 6-14h, nghỉ giữa ca 30 phút, T2-T7.",
},
new ShiftPattern
{
Code = "CA2", Name = "Ca chiều",
StartTime = new TimeOnly(14, 0), EndTime = new TimeOnly(22, 0),
BreakMinutes = 30, WorkDays = "Mon,Tue,Wed,Thu,Fri,Sat",
Description = "Ca chiều 14-22h, nghỉ giữa ca 30 phút, T2-T7.",
});
}
// 1 OtPolicy default — Luật Lao động VN cap.
if (!await db.OtPolicies.AnyAsync())
{
db.OtPolicies.Add(new OtPolicy
{
Code = "STANDARD",
Name = "Chính sách OT chuẩn",
MultiplierWeekday = 1.5m,
MultiplierWeekend = 2.0m,
MultiplierHoliday = 3.0m,
MaxHoursPerDay = 4,
MaxHoursPerMonth = 40,
MaxHoursPerYear = 200,
Description = "Hệ số 1.5x/2.0x/3.0x theo Luật Lao động VN 2019. Max 4h/ngày, 40h/tháng, 200h/năm.",
});
}
await db.SaveChangesAsync();
logger.LogInformation("SeedHrmConfigsAsync: seeded 5 LeaveTypes + 10 Holidays 2026 + 3 ShiftPatterns + 1 OtPolicy default.");
}
}

View File

@ -0,0 +1,159 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SolutionErp.Infrastructure.Persistence.Migrations
{
/// <inheritdoc />
public partial class AddHrmConfigs : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Holidays",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Year = table.Column<int>(type: "int", nullable: false),
Date = table.Column<DateOnly>(type: "date", nullable: false),
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
IsRecurring = table.Column<bool>(type: "bit", nullable: false),
IsPaid = table.Column<bool>(type: "bit", nullable: false),
IsActive = table.Column<bool>(type: "bit", nullable: false),
Description = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
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_Holidays", x => x.Id);
});
migrationBuilder.CreateTable(
name: "LeaveTypes",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Code = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
DaysPerYear = table.Column<decimal>(type: "decimal(5,2)", nullable: false),
IsPaid = table.Column<bool>(type: "bit", nullable: false),
RequiresAttachment = table.Column<bool>(type: "bit", nullable: false),
IsActive = table.Column<bool>(type: "bit", nullable: false),
Description = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
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_LeaveTypes", x => x.Id);
});
migrationBuilder.CreateTable(
name: "OtPolicies",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Code = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
MultiplierWeekday = table.Column<decimal>(type: "decimal(4,2)", nullable: false),
MultiplierWeekend = table.Column<decimal>(type: "decimal(4,2)", nullable: false),
MultiplierHoliday = table.Column<decimal>(type: "decimal(4,2)", nullable: false),
MaxHoursPerDay = table.Column<int>(type: "int", nullable: false),
MaxHoursPerMonth = table.Column<int>(type: "int", nullable: false),
MaxHoursPerYear = table.Column<int>(type: "int", nullable: false),
IsActive = table.Column<bool>(type: "bit", nullable: false),
Description = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
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_OtPolicies", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ShiftPatterns",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Code = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
StartTime = table.Column<TimeOnly>(type: "time", nullable: false),
EndTime = table.Column<TimeOnly>(type: "time", nullable: false),
BreakMinutes = table.Column<int>(type: "int", nullable: false),
WorkDays = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
IsActive = table.Column<bool>(type: "bit", nullable: false),
Description = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UpdatedBy = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
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_ShiftPatterns", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_Holidays_Year_Date",
table: "Holidays",
columns: new[] { "Year", "Date" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_LeaveTypes_Code",
table: "LeaveTypes",
column: "Code",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_OtPolicies_Code",
table: "OtPolicies",
column: "Code",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ShiftPatterns_Code",
table: "ShiftPatterns",
column: "Code",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Holidays");
migrationBuilder.DropTable(
name: "LeaveTypes");
migrationBuilder.DropTable(
name: "OtPolicies");
migrationBuilder.DropTable(
name: "ShiftPatterns");
}
}
}

View File

@ -2494,6 +2494,262 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.ToTable("EmployeeWorkHistories", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Hrm.Holiday", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<DateOnly>("Date")
.HasColumnType("date");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("DeletedBy")
.HasColumnType("uniqueidentifier");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<bool>("IsActive")
.HasColumnType("bit");
b.Property<bool>("IsDeleted")
.HasColumnType("bit");
b.Property<bool>("IsPaid")
.HasColumnType("bit");
b.Property<bool>("IsRecurring")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.Property<int>("Year")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("Year", "Date")
.IsUnique();
b.ToTable("Holidays", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Hrm.LeaveType", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("Code")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uniqueidentifier");
b.Property<decimal>("DaysPerYear")
.HasColumnType("decimal(5,2)");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("DeletedBy")
.HasColumnType("uniqueidentifier");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<bool>("IsActive")
.HasColumnType("bit");
b.Property<bool>("IsDeleted")
.HasColumnType("bit");
b.Property<bool>("IsPaid")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<bool>("RequiresAttachment")
.HasColumnType("bit");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("Code")
.IsUnique();
b.ToTable("LeaveTypes", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Hrm.OtPolicy", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("Code")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
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<string>("Description")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<bool>("IsActive")
.HasColumnType("bit");
b.Property<bool>("IsDeleted")
.HasColumnType("bit");
b.Property<int>("MaxHoursPerDay")
.HasColumnType("int");
b.Property<int>("MaxHoursPerMonth")
.HasColumnType("int");
b.Property<int>("MaxHoursPerYear")
.HasColumnType("int");
b.Property<decimal>("MultiplierHoliday")
.HasColumnType("decimal(4,2)");
b.Property<decimal>("MultiplierWeekday")
.HasColumnType("decimal(4,2)");
b.Property<decimal>("MultiplierWeekend")
.HasColumnType("decimal(4,2)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("Code")
.IsUnique();
b.ToTable("OtPolicies", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Hrm.ShiftPattern", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<int>("BreakMinutes")
.HasColumnType("int");
b.Property<string>("Code")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("nvarchar(20)");
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<string>("Description")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<TimeOnly>("EndTime")
.HasColumnType("time");
b.Property<bool>("IsActive")
.HasColumnType("bit");
b.Property<bool>("IsDeleted")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<TimeOnly>("StartTime")
.HasColumnType("time");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uniqueidentifier");
b.Property<string>("WorkDays")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.HasKey("Id");
b.HasIndex("Code")
.IsUnique();
b.ToTable("ShiftPatterns", (string)null);
});
modelBuilder.Entity("SolutionErp.Domain.Identity.MenuItem", b =>
{
b.Property<string>("Key")