Files
blazor-saas-hrm/Infrastructure/Database/DatabaseSeeder.cs
T
2026-07-21 14:22:06 +07:00

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();
}
}