713 lines
33 KiB
C#
713 lines
33 KiB
C#
using Indotalent.ConfigBackEnd.Interfaces;
|
|
using Indotalent.Data.Entities;
|
|
using Indotalent.Infrastructure.Authentication.Identity;
|
|
using Indotalent.Infrastructure.Authorization.Identity;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace Indotalent.Infrastructure.Database;
|
|
|
|
public static class DatabaseSeeder
|
|
{
|
|
private static string? adminUserId;
|
|
private static string? tenantId;
|
|
|
|
public static async Task SeedAsync(IServiceProvider serviceProvider)
|
|
{
|
|
var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
|
|
var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
|
var configuration = serviceProvider.GetRequiredService<IConfiguration>();
|
|
var context = serviceProvider.GetRequiredService<AppDbContext>();
|
|
|
|
var currentUserService = serviceProvider.GetRequiredService<ICurrentUserService>();
|
|
|
|
await SeedIdentityAsync(roleManager, userManager, configuration);
|
|
currentUserService.UserId = adminUserId;
|
|
|
|
await SeedDemoTenantAsync(context);
|
|
currentUserService.TenantId = tenantId;
|
|
|
|
await SeedCurrenciesAsync(context);
|
|
await SeedCompanyAsync(context);
|
|
await SeedTaxAsync(context);
|
|
await SeedBranchAsync(context);
|
|
await SeedDepartmentAsync(context);
|
|
await SeedDesignationAsync(context);
|
|
await SeedGradeAsync(context);
|
|
await SeedIncomeAsync(context);
|
|
await SeedDeductionAsync(context);
|
|
await SeedEmployeeAsync(context);
|
|
await SeedLeaveCategoryAsync(context);
|
|
await SeedLeaveBalanceAsync(context);
|
|
await SeedLeaveRequestAsync(context);
|
|
await SeedEvaluationAsync(context);
|
|
await SeedAppraisalAsync(context);
|
|
await SeedPromotionAsync(context);
|
|
await SeedTransferAsync(context);
|
|
await SeedPayrollAsync(context);
|
|
}
|
|
private static async Task SeedDemoTenantAsync(AppDbContext context)
|
|
{
|
|
var existingTenant = await context.Set<Tenant>().FirstOrDefaultAsync(t => t.Name == "Demo Tenant");
|
|
|
|
if (existingTenant == null)
|
|
{
|
|
var newTenant = new Tenant
|
|
{
|
|
Name = "Demo Tenant",
|
|
Description = "Initial system tenant for demonstration and seed data.",
|
|
Street = "Sudirman Street No. 123",
|
|
City = "Bandung",
|
|
State = "West Java",
|
|
ZipCode = "40111",
|
|
Country = "Indonesia",
|
|
PhoneNumber = "+62221234567",
|
|
EmailAddress = "hi@indotalent.com",
|
|
Website = "https://indotalent.com",
|
|
IsActive = true
|
|
};
|
|
|
|
await context.Set<Tenant>().AddAsync(newTenant);
|
|
await context.SaveChangesAsync();
|
|
|
|
tenantId = newTenant.Id;
|
|
}
|
|
else
|
|
{
|
|
tenantId = existingTenant.Id;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(adminUserId) && !string.IsNullOrEmpty(tenantId))
|
|
{
|
|
var isMapped = await context.Set<TenantUser>()
|
|
.AnyAsync(tu => tu.TenantId == tenantId && tu.UserId == adminUserId);
|
|
|
|
if (!isMapped)
|
|
{
|
|
var tenantUser = new TenantUser
|
|
{
|
|
TenantId = tenantId,
|
|
UserId = adminUserId,
|
|
Summary = "Administrator default member mapping",
|
|
IsActive = true
|
|
};
|
|
|
|
await context.Set<TenantUser>().AddAsync(tenantUser);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static async Task SeedIdentityAsync(RoleManager<IdentityRole> roleManager, UserManager<ApplicationUser> userManager, IConfiguration configuration)
|
|
{
|
|
var adminSettings = configuration.GetSection("IdentitySettings:DefaultAdmin").Get<DefaultAdminSettings>();
|
|
if (adminSettings == null) return;
|
|
|
|
foreach (var roleName in ApplicationRoles.AllRoles)
|
|
{
|
|
if (!await roleManager.RoleExistsAsync(roleName))
|
|
{
|
|
await roleManager.CreateAsync(new IdentityRole(roleName));
|
|
}
|
|
}
|
|
|
|
var existingUser = await userManager.FindByEmailAsync(adminSettings.Email);
|
|
if (existingUser == null)
|
|
{
|
|
var defaultAdmin = DefaultUserConfig.GetAdminUser(adminSettings);
|
|
var createAdmin = await userManager.CreateAsync(defaultAdmin, adminSettings.Password);
|
|
|
|
if (createAdmin.Succeeded)
|
|
{
|
|
await userManager.AddToRolesAsync(defaultAdmin, ApplicationRoles.AllRoles);
|
|
adminUserId = defaultAdmin.Id;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static async Task SeedCurrenciesAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Currency>().AnyAsync()) return;
|
|
|
|
var currencies = new List<Currency>
|
|
{
|
|
new() { Name = "US Dollar", Code = "USD", Symbol = "$", Description = "United States official currency", CountryOwner = "United States" },
|
|
new() { Name = "Euro", Code = "EUR", Symbol = "€", Description = "Eurozone member states currency", CountryOwner = "European Union" },
|
|
new() { Name = "British Pound", Code = "GBP", Symbol = "£", Description = "Official currency of the UK", CountryOwner = "United Kingdom" },
|
|
new() { Name = "Indonesian Rupiah", Code = "IDR", Symbol = "Rp", Description = "Official currency of Indonesia", CountryOwner = "Indonesia" }
|
|
};
|
|
|
|
await context.Set<Currency>().AddRangeAsync(currencies);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedCompanyAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Company>().AnyAsync()) return;
|
|
|
|
var usdCurrency = await context.Set<Currency>().FirstOrDefaultAsync(x => x.Code == "USD");
|
|
if (usdCurrency == null) return;
|
|
|
|
var companies = new List<Company>
|
|
{
|
|
new()
|
|
{
|
|
Name = "Acme Global Solutions Inc.",
|
|
Description = "A leading provider of enterprise-grade cloud software solutions.",
|
|
IsDefault = true,
|
|
CurrencyId = usdCurrency.Id,
|
|
TaxIdentification = "EIN 12-3456789",
|
|
BusinessLicense = "LC-987654321",
|
|
StreetAddress = "One World Trade Center, Suite 85",
|
|
City = "New York",
|
|
StateProvince = "NY",
|
|
ZipCode = "10007",
|
|
Phone = "+1 212 555 0198",
|
|
Email = "hr@acmeglobal.com",
|
|
SocialMediaLinkedIn = "linkedin.com/company/acme-global",
|
|
CompanyLogo = "/images/logos/acme-logo.png",
|
|
OtherInformation1 = "Corporate Headquarters",
|
|
OtherInformation2 = "Technology & SaaS",
|
|
OtherInformation3 = "Fortune 500 Candidate"
|
|
}
|
|
};
|
|
|
|
await context.Set<Company>().AddRangeAsync(companies);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedTaxAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Tax>().AnyAsync()) return;
|
|
|
|
var taxes = new List<Tax>
|
|
{
|
|
new() { Code = "FED-INC", Name = "Federal Income Tax", Description = "US Federal Progressive Income Tax", PercentageValue = 22, Category = "Income Tax" },
|
|
new() { Code = "SS-TAX", Name = "Social Security", Description = "Social Security (OASDI)", PercentageValue = 6.2m, Category = "Statutory" },
|
|
new() { Code = "MED-TAX", Name = "Medicare", Description = "Medicare Hospital Insurance", PercentageValue = 1.45m, Category = "Statutory" },
|
|
new() { Code = "NY-STATE", Name = "NY State Tax", Description = "New York State Income Tax", PercentageValue = 5.8m, Category = "State Tax" },
|
|
new() { Code = "NY-CITY", Name = "NYC Local Tax", Description = "New York City Local Tax", PercentageValue = 3.5m, Category = "Local Tax" }
|
|
};
|
|
|
|
await context.Set<Tax>().AddRangeAsync(taxes);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedBranchAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Branch>().AnyAsync()) return;
|
|
|
|
var branches = new List<Branch>
|
|
{
|
|
new() { Name = "New York HQ", City = "New York", StreetAddress = "One World Trade Center", Phone = "+1 212 555 0101", Code = "US-NYC" },
|
|
new() { Name = "San Francisco Tech Center", City = "San Francisco", StreetAddress = "Market Street, Financial District", Phone = "+1 415 555 0202", Code = "US-SFO" },
|
|
new() { Name = "Chicago Operations", City = "Chicago", StreetAddress = "Willis Tower, 233 S Wacker Dr", Phone = "+1 312 555 0303", Code = "US-CHI" },
|
|
new() { Name = "Austin Innovation Hub", City = "Austin", StreetAddress = "Congress Avenue, Downtown", Phone = "+1 512 555 0404", Code = "US-AUS" },
|
|
new() { Name = "Seattle Cloud Office", City = "Seattle", StreetAddress = "Westlake Ave, South Lake Union", Phone = "+1 206 555 0505", Code = "US-SEA" }
|
|
};
|
|
|
|
await context.Set<Branch>().AddRangeAsync(branches);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedDepartmentAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Department>().AnyAsync()) return;
|
|
|
|
var departments = new List<Department>
|
|
{
|
|
new() { CostCenter = "US-IT", Name = "Engineering & IT", HeadOfDeptartment = "Michael Scott", Description = "Software engineering and cloud infrastructure." },
|
|
new() { CostCenter = "US-HR", Name = "People & Culture", HeadOfDeptartment = "Pam Beesly", Description = "Talent acquisition and employee experience." },
|
|
new() { CostCenter = "US-FIN", Name = "Finance", HeadOfDeptartment = "Angela Martin", Description = "Global financial planning and analysis." },
|
|
new() { CostCenter = "US-MKT", Name = "Marketing", HeadOfDeptartment = "Ryan Howard", Description = "Digital marketing and brand growth." },
|
|
new() { CostCenter = "US-SAL", Name = "Global Sales", HeadOfDeptartment = "Jim Halpert", Description = "Enterprise sales and business development." }
|
|
};
|
|
|
|
await context.Set<Department>().AddRangeAsync(departments);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedDesignationAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Designation>().AnyAsync()) return;
|
|
|
|
var designations = new List<Designation>
|
|
{
|
|
new() { Code = "C-LEVEL", Name = "Chief Executive Officer", Level = "Executive", Description = "Global strategy Lead." },
|
|
new() { Code = "DIR-01", Name = "Director of Engineering", Level = "Director", Description = "Engineering organization Lead." },
|
|
new() { Code = "MGR-01", Name = "Engineering Manager", Level = "Management", Description = "Team and project management." },
|
|
new() { Code = "ENG-01", Name = "Principal Software Engineer", Level = "Professional", Description = "Systems architecture." },
|
|
new() { Code = "ENG-02", Name = "Senior Software Engineer", Level = "Professional", Description = "Full-stack development." },
|
|
new() { Code = "ENG-03", Name = "Cloud Architect", Level = "Professional", Description = "Azure/AWS Infrastructure." }
|
|
};
|
|
|
|
await context.Set<Designation>().AddRangeAsync(designations);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedIncomeAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Income>().AnyAsync()) return;
|
|
|
|
var incomes = new List<Income>
|
|
{
|
|
new() { Code = "BASE", Name = "Base Salary", Type = "Fixed", IsTaxable = true, CalculationBase = "Contracted salary", Status = "Active", Description = "Monthly base compensation" },
|
|
new() { Code = "BONUS", Name = "Performance Bonus", Type = "Variable", IsTaxable = true, CalculationBase = "Quarterly KPI Result", Status = "Active", Description = "KPI based performance incentive" },
|
|
// Di US umum ada Stipend atau Reimbursement
|
|
new() { Code = "WFH", Name = "WFH Stipend", Type = "Fixed", IsTaxable = false, CalculationBase = "Remote work support", Status = "Active", Description = "Internet and utilities allowance" },
|
|
new() { Code = "CAR", Name = "Car Allowance", Type = "Fixed", IsTaxable = true, CalculationBase = "Executive car benefit", Status = "Active", Description = "Executive transportation support" }
|
|
};
|
|
|
|
await context.Set<Income>().AddRangeAsync(incomes);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedDeductionAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Deduction>().AnyAsync()) return;
|
|
|
|
var deductions = new List<Deduction>
|
|
{
|
|
new() { Code = "FIT", Name = "Federal Income Tax", Category = "Statutory", PreTax = false, CalculationMethod = "IRS Tax Tables", Status = "Active", Description = "Mandatory Federal Tax" },
|
|
new() { Code = "401K", Name = "401(k) Contribution", Category = "Retirement", PreTax = true, CalculationMethod = "% of Gross Salary", Status = "Active", Description = "Voluntary retirement savings" },
|
|
new() { Code = "HLTH", Name = "Health Insurance Premium", Category = "Insurance", PreTax = true, CalculationMethod = "Flat employee portion", Status = "Active", Description = "Medical/Dental/Vision premium" },
|
|
new() { Code = "LIFE", Name = "Group Life Insurance", Category = "Insurance", PreTax = false, CalculationMethod = "Fixed premium", Status = "Active", Description = "Optional life insurance coverage" }
|
|
};
|
|
|
|
await context.Set<Deduction>().AddRangeAsync(deductions);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedGradeAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Grade>().AnyAsync()) return;
|
|
|
|
var grades = new List<Grade>
|
|
{
|
|
new() { Code = "L-01", Name = "Executive Level", Description = "C-Suite and VPs", SalaryFrom = 180000, SalaryTo = 350000, IsOverTimeEligible = false, Status = "Active" },
|
|
new() { Code = "L-02", Name = "Director Level", Description = "Department Directors", SalaryFrom = 140000, SalaryTo = 200000, IsOverTimeEligible = false, Status = "Active" },
|
|
new() { Code = "L-03", Name = "Management Level", Description = "Engineering/Product Managers", SalaryFrom = 110000, SalaryTo = 160000, IsOverTimeEligible = false, Status = "Active" },
|
|
new() { Code = "L-04", Name = "Senior Professional", Description = "Senior IC Roles", SalaryFrom = 95000, SalaryTo = 145000, IsOverTimeEligible = true, Status = "Active" },
|
|
new() { Code = "L-05", Name = "Professional", Description = "Mid-Level IC Roles", SalaryFrom = 70000, SalaryTo = 100000, IsOverTimeEligible = true, Status = "Active" }
|
|
};
|
|
|
|
await context.Set<Grade>().AddRangeAsync(grades);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedEmployeeAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Employee>().AnyAsync()) return;
|
|
|
|
var hqBranch = await context.Set<Branch>().FirstOrDefaultAsync(x => x.Code == "US-NYC");
|
|
var itDept = await context.Set<Department>().FirstOrDefaultAsync(x => x.CostCenter == "US-IT");
|
|
var managerDesig = await context.Set<Designation>().FirstOrDefaultAsync(x => x.Code == "MGR-01");
|
|
var allGrades = await context.Set<Grade>().ToListAsync();
|
|
|
|
var wfhStipend = await context.Set<Income>().FirstOrDefaultAsync(x => x.Code == "WFH");
|
|
var healthIns = await context.Set<Deduction>().FirstOrDefaultAsync(x => x.Code == "HLTH");
|
|
var retirement401k = await context.Set<Deduction>().FirstOrDefaultAsync(x => x.Code == "401K");
|
|
|
|
if (hqBranch == null || itDept == null || managerDesig == null || !allGrades.Any()) return;
|
|
|
|
var random = new Random();
|
|
var employees = new List<Employee>();
|
|
var empIncomes = new List<EmployeeIncome>();
|
|
var empDeductions = new List<EmployeeDeduction>();
|
|
|
|
// Nama-nama Amerika
|
|
string[] firstNames = { "James", "Robert", "John", "Michael", "David", "William", "Richard", "Joseph", "Thomas", "Christopher", "Charles", "Daniel", "Matthew", "Anthony", "Mark", "Donald", "Steven", "Paul", "Andrew", "Joshua", "Emily", "Mary", "Patricia", "Jennifer", "Linda", "Elizabeth", "Barbara", "Susan", "Jessica", "Sarah" };
|
|
string[] lastNames = { "Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis", "Rodriguez", "Martinez", "Hernandez", "Lopez", "Gonzales", "Wilson", "Anderson", "Thomas", "Taylor", "Moore", "Jackson", "Martin", "Lee", "Perez", "Thompson", "White", "Harris", "Sanchez", "Clark", "Ramirez", "Lewis", "Robinson" };
|
|
string[] banks = { "JP Morgan Chase", "Bank of America", "Wells Fargo", "Citibank", "Capital One" };
|
|
|
|
for (int i = 1; i <= 30; i++)
|
|
{
|
|
var fName = firstNames[random.Next(firstNames.Length)];
|
|
var lName = lastNames[random.Next(lastNames.Length)];
|
|
var selectedGrade = allGrades[random.Next(allGrades.Count)];
|
|
|
|
// Perhitungan Gaji Tahunan (Annual) dibagi 12
|
|
var salaryRange = selectedGrade.SalaryTo - selectedGrade.SalaryFrom;
|
|
var baseAnnualSalary = selectedGrade.SalaryFrom + (decimal)(random.NextDouble() * (double)salaryRange);
|
|
var baseSalary = Math.Round(baseAnnualSalary / 12, 0);
|
|
|
|
var emp = new Employee
|
|
{
|
|
Code = $"ACME-{2000 + i}",
|
|
FirstName = fName,
|
|
LastName = lName,
|
|
JobDescription = "Specialized staff contributing to regional US operations.",
|
|
GradeId = selectedGrade.Id,
|
|
BasicSalary = baseSalary,
|
|
SalaryBankName = banks[random.Next(banks.Length)],
|
|
SalaryBankAccountName = $"{fName} {lName}",
|
|
SalaryBankAccountNumber = $"{random.Next(100, 999)}-{random.Next(100000, 999999)}",
|
|
PlaceOfBirth = "USA",
|
|
DateOfBirth = new DateTime(random.Next(1975, 2000), random.Next(1, 12), random.Next(1, 28)),
|
|
Gender = i % 2 == 0 ? "Female" : "Male",
|
|
MaritalStatus = "Single",
|
|
Religion = "Christian",
|
|
IdentityNumber = $"SSN-{random.Next(100, 999)}-{random.Next(10, 99)}-{random.Next(1000, 9999)}",
|
|
JoinedDate = new DateTime(2022, 1, 1).AddMonths(-random.Next(1, 48)),
|
|
EmployeeStatus = "Active",
|
|
EmploymentType = "Full-Time",
|
|
Email = $"{fName.ToLower()}.{lName.ToLower()}@acmeglobal.com",
|
|
BranchId = hqBranch.Id,
|
|
DepartmentId = itDept.Id,
|
|
DesignationId = managerDesig.Id
|
|
};
|
|
|
|
employees.Add(emp);
|
|
|
|
if (wfhStipend != null)
|
|
{
|
|
empIncomes.Add(new EmployeeIncome
|
|
{
|
|
Employee = emp,
|
|
IncomeId = wfhStipend.Id,
|
|
Amount = 150, // USD 150 per month
|
|
Description = "Remote work utilities support",
|
|
IsActive = true
|
|
});
|
|
}
|
|
|
|
if (healthIns != null)
|
|
{
|
|
empDeductions.Add(new EmployeeDeduction
|
|
{
|
|
Employee = emp,
|
|
DeductionId = healthIns.Id,
|
|
Amount = 250, // USD 250 flat per month for insurance
|
|
Description = "Employee medical premium",
|
|
IsActive = true
|
|
});
|
|
}
|
|
|
|
if (retirement401k != null)
|
|
{
|
|
empDeductions.Add(new EmployeeDeduction
|
|
{
|
|
Employee = emp,
|
|
DeductionId = retirement401k.Id,
|
|
Amount = Math.Round(baseSalary * 0.05m, 0), // 5% for 401k
|
|
Description = "401(k) retirement plan contribution",
|
|
IsActive = true
|
|
});
|
|
}
|
|
}
|
|
|
|
await context.Set<Employee>().AddRangeAsync(employees);
|
|
await context.Set<EmployeeIncome>().AddRangeAsync(empIncomes);
|
|
await context.Set<EmployeeDeduction>().AddRangeAsync(empDeductions);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedLeaveCategoryAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<LeaveCategory>().AnyAsync()) return;
|
|
|
|
var categories = new List<LeaveCategory>
|
|
{
|
|
new() { Code = "US-PTO", Name = "Paid Time Off (PTO)", Quota = 20, IsPaidLeave = true, Description = "Vacation and personal days", Status = "Active" },
|
|
new() { Code = "US-SICK", Name = "Sick Leave", Quota = 10, IsPaidLeave = true, Description = "Medical leave with notification", Status = "Active" },
|
|
new() { Code = "US-BEREAVE", Name = "Bereavement Leave", Quota = 5, IsPaidLeave = true, Description = "Loss of immediate family members", Status = "Active" },
|
|
new() { Code = "US-JURY", Name = "Jury Duty", Quota = 0, IsPaidLeave = true, Description = "Court-mandated duty", Status = "Active" },
|
|
new() { Code = "US-FMLA", Name = "Family Medical Leave (FMLA)", Quota = 60, IsPaidLeave = false, Description = "Long-term medical or family care", Status = "Active" }
|
|
};
|
|
|
|
await context.Set<LeaveCategory>().AddRangeAsync(categories);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedLeaveBalanceAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<LeaveBalance>().AnyAsync()) return;
|
|
|
|
var employees = await context.Set<Employee>().Take(15).ToListAsync();
|
|
var ptoLeave = await context.Set<LeaveCategory>().FirstOrDefaultAsync(x => x.Code == "US-PTO");
|
|
|
|
if (!employees.Any() || ptoLeave == null) return;
|
|
|
|
var balances = new List<LeaveBalance>();
|
|
foreach (var emp in employees)
|
|
{
|
|
balances.Add(new LeaveBalance
|
|
{
|
|
EmployeeId = emp.Id,
|
|
LeaveCategoryId = ptoLeave.Id,
|
|
Entitlement = ptoLeave.Quota,
|
|
Used = 5,
|
|
Pending = 0,
|
|
Remaining = ptoLeave.Quota - 5,
|
|
Year = 2026,
|
|
ValidFrom = new DateTime(2026, 1, 1),
|
|
ValidTo = new DateTime(2026, 12, 31)
|
|
});
|
|
}
|
|
|
|
await context.Set<LeaveBalance>().AddRangeAsync(balances);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedLeaveRequestAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<LeaveRequest>().AnyAsync()) return;
|
|
|
|
var categories = await context.Set<LeaveCategory>().ToListAsync();
|
|
var employees = await context.Set<Employee>().ToListAsync();
|
|
|
|
var requests = new List<LeaveRequest>();
|
|
|
|
var mockData = new[] {
|
|
new { Name = "James", Cat = "US-PTO", Start = DateTime.Now.AddDays(10), End = DateTime.Now.AddDays(14), Days = 5.0, Status = "Approved", Reason = "Grand Canyon trip" },
|
|
new { Name = "Emily", Cat = "US-SICK", Start = DateTime.Now.AddDays(-3), End = DateTime.Now.AddDays(-1), Days = 3.0, Status = "Approved", Reason = "Medical checkup" },
|
|
new { Name = "Robert", Cat = "US-PTO", Start = DateTime.Now.AddDays(20), End = DateTime.Now.AddDays(22), Days = 3.0, Status = "Pending", Reason = "Family reunion in Texas" }
|
|
};
|
|
|
|
foreach (var item in mockData)
|
|
{
|
|
var emp = employees.FirstOrDefault(x => x.FirstName.Contains(item.Name));
|
|
var cat = categories.FirstOrDefault(x => x.Code == item.Cat);
|
|
|
|
if (emp != null && cat != null)
|
|
{
|
|
requests.Add(new LeaveRequest
|
|
{
|
|
EmployeeId = emp.Id,
|
|
LeaveCategoryId = cat.Id,
|
|
StartDate = item.Start,
|
|
EndDate = item.End,
|
|
Days = item.Days,
|
|
Status = item.Status,
|
|
Reason = item.Reason
|
|
});
|
|
}
|
|
}
|
|
|
|
await context.Set<LeaveRequest>().AddRangeAsync(requests);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedEvaluationAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Evaluation>().AnyAsync()) return;
|
|
|
|
var allEmployees = await context.Set<Employee>().ToListAsync();
|
|
if (allEmployees.Count < 5) return;
|
|
|
|
var evaluations = new List<Evaluation>();
|
|
var random = new Random();
|
|
|
|
for (int i = 0; i < Math.Min(20, allEmployees.Count); i++)
|
|
{
|
|
var targetEmployee = allEmployees[i];
|
|
var potentialEvaluators = allEmployees.Where(x => x.Id != targetEmployee.Id).ToList();
|
|
var evaluator = potentialEvaluators[random.Next(potentialEvaluators.Count)];
|
|
|
|
evaluations.Add(new Evaluation
|
|
{
|
|
EmployeeId = targetEmployee.Id,
|
|
Period = "Annual 2025 Review",
|
|
FinalScore = (85 + random.Next(1, 15)).ToString("F1"),
|
|
Rating = (random.Next(3, 5)).ToString(),
|
|
EvaluatorId = evaluator.Id,
|
|
EvaluationDate = DateTime.Now.AddDays(-random.Next(1, 60)),
|
|
EvaluationNote = "Employee demonstrates exceptional leadership and technical proficiency.",
|
|
Status = "Completed"
|
|
});
|
|
}
|
|
|
|
await context.Set<Evaluation>().AddRangeAsync(evaluations);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedAppraisalAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Appraisal>().AnyAsync()) return;
|
|
var employees = await context.Set<Employee>().Skip(5).Take(15).ToListAsync();
|
|
var appraisals = new List<Appraisal>();
|
|
var ratings = new[] { "Exceeds Expectations", "Consistently High", "Outstanding" };
|
|
|
|
for (int i = 0; i < 15; i++)
|
|
{
|
|
decimal salary = employees[i].BasicSalary;
|
|
decimal incPercent = 3 + (i % 5);
|
|
appraisals.Add(new Appraisal
|
|
{
|
|
EmployeeId = employees[i].Id,
|
|
LastRating = ratings[i % ratings.Length],
|
|
CurrentSalary = salary,
|
|
IncrementPercentage = incPercent,
|
|
NewSalary = salary + (salary * incPercent / 100),
|
|
AppraisalType = "Annual Merit Increase",
|
|
EffectiveDate = DateTime.Now.AddMonths(1),
|
|
AppraisalNote = "Standard US merit increase based on FY2025 performance.",
|
|
Status = "Approved"
|
|
});
|
|
}
|
|
await context.Set<Appraisal>().AddRangeAsync(appraisals);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedPromotionAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Promotion>().AnyAsync()) return;
|
|
var employees = await context.Set<Employee>().Skip(2).Take(10).ToListAsync();
|
|
var promotions = new List<Promotion>();
|
|
var grades = new[] { "L-05", "L-04", "L-03", "L-02" };
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
promotions.Add(new Promotion
|
|
{
|
|
EmployeeId = employees[i].Id,
|
|
FromGrade = grades[0],
|
|
ToGrade = grades[1],
|
|
EffectiveDate = DateTime.Now.AddDays(i + 10),
|
|
PromotionNote = "Promoted to Senior level for architectural excellence.",
|
|
Status = "Confirmed"
|
|
});
|
|
}
|
|
await context.Set<Promotion>().AddRangeAsync(promotions);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedTransferAsync(AppDbContext context)
|
|
{
|
|
if (await context.Set<Transfer>().AnyAsync()) return;
|
|
var employees = await context.Set<Employee>().Take(10).ToListAsync();
|
|
var branches = await context.Set<Branch>().ToListAsync();
|
|
var depts = await context.Set<Department>().ToListAsync();
|
|
var desigs = await context.Set<Designation>().ToListAsync();
|
|
var transfers = new List<Transfer>();
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
transfers.Add(new Transfer
|
|
{
|
|
EmployeeId = employees[i].Id,
|
|
FromBranchId = branches[0].Id,
|
|
ToBranchId = branches[1].Id,
|
|
FromDepartmentId = depts[0].Id,
|
|
ToDepartmentId = depts[0].Id,
|
|
FromDesignationId = desigs[4].Id,
|
|
ToDesignationId = desigs[3].Id,
|
|
TransferDate = DateTime.Now.AddDays(i + 5),
|
|
TransferNote = "Relocation to SFO for Cloud Project acceleration.",
|
|
Status = "Active"
|
|
});
|
|
}
|
|
await context.Set<Transfer>().AddRangeAsync(transfers);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
private static async Task SeedPayrollAsync(AppDbContext context)
|
|
{
|
|
if (await context.PayrollProcess.AnyAsync()) return;
|
|
|
|
var employees = await context.Employee
|
|
.Include(x => x.EmployeeIncome)
|
|
.Include(x => x.EmployeeDeduction)
|
|
.ToListAsync();
|
|
|
|
if (!employees.Any()) return;
|
|
|
|
var payrollProcesses = new List<PayrollProcess>();
|
|
var payrollDetails = new List<PayrollDetail>();
|
|
var payrollComponents = new List<PayrollComponent>();
|
|
|
|
for (int m = 2; m >= 0; m--)
|
|
{
|
|
var date = DateTime.Now.AddMonths(-m);
|
|
var periodName = date.ToString("MMMM yyyy");
|
|
var fromDate = new DateTime(date.Year, date.Month, 1);
|
|
var toDate = fromDate.AddMonths(1).AddDays(-1);
|
|
|
|
var process = new PayrollProcess
|
|
{
|
|
Id = Guid.NewGuid().ToString(),
|
|
AutoNumber = $"US-PAY-{date:yyyyMM}-{3 - m:D3}",
|
|
PeriodName = periodName,
|
|
FromDate = fromDate,
|
|
ToDate = toDate,
|
|
Status = "Paid",
|
|
ProcessedBy = "US Payroll Admin",
|
|
ProcessedAt = DateTime.Now.AddMonths(-m),
|
|
Description = $"Global US Payroll processing for {periodName}"
|
|
};
|
|
|
|
decimal grandBasic = 0, grandIncome = 0, grandDeduction = 0;
|
|
|
|
foreach (var emp in employees)
|
|
{
|
|
var totalInc = emp.EmployeeIncome?.Sum(x => x.Amount) ?? 0;
|
|
var totalDed = emp.EmployeeDeduction?.Sum(x => x.Amount) ?? 0;
|
|
var thp = emp.BasicSalary + totalInc - totalDed;
|
|
|
|
var detail = new PayrollDetail
|
|
{
|
|
Id = Guid.NewGuid().ToString(),
|
|
PayrollProcessId = process.Id,
|
|
EmployeeId = emp.Id,
|
|
EmployeeCode = emp.Code,
|
|
EmployeeName = $"{emp.FirstName} {emp.LastName}",
|
|
BasicSalary = emp.BasicSalary,
|
|
TotalIncome = totalInc,
|
|
TotalDeduction = totalDed,
|
|
TakeHomePay = thp
|
|
};
|
|
|
|
if (emp.EmployeeIncome != null)
|
|
{
|
|
foreach (var inc in emp.EmployeeIncome)
|
|
{
|
|
payrollComponents.Add(new PayrollComponent
|
|
{
|
|
Id = Guid.NewGuid().ToString(),
|
|
PayrollDetailId = detail.Id,
|
|
ComponentName = inc.Income?.Name,
|
|
ComponentType = "Income",
|
|
Amount = inc.Amount,
|
|
Description = inc.Description
|
|
});
|
|
}
|
|
}
|
|
|
|
if (emp.EmployeeDeduction != null)
|
|
{
|
|
foreach (var ded in emp.EmployeeDeduction)
|
|
{
|
|
payrollComponents.Add(new PayrollComponent
|
|
{
|
|
Id = Guid.NewGuid().ToString(),
|
|
PayrollDetailId = detail.Id,
|
|
ComponentName = ded.Deduction?.Name,
|
|
ComponentType = "Deduction",
|
|
Amount = ded.Amount,
|
|
Description = ded.Description
|
|
});
|
|
}
|
|
}
|
|
|
|
grandBasic += detail.BasicSalary;
|
|
grandIncome += totalInc;
|
|
grandDeduction += totalDed;
|
|
payrollDetails.Add(detail);
|
|
}
|
|
|
|
process.TotalEmployees = employees.Count;
|
|
process.TotalBasicSalary = grandBasic;
|
|
process.TotalIncome = grandIncome;
|
|
process.TotalDeduction = grandDeduction;
|
|
process.TotalGross = grandBasic + grandIncome;
|
|
process.TotalTakeHomePay = process.TotalGross - grandDeduction;
|
|
|
|
payrollProcesses.Add(process);
|
|
}
|
|
|
|
await context.PayrollProcess.AddRangeAsync(payrollProcesses);
|
|
await context.PayrollDetail.AddRangeAsync(payrollDetails);
|
|
await context.PayrollComponent.AddRangeAsync(payrollComponents);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
} |