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 { public static async Task SeedAsync(IServiceProvider serviceProvider) { var roleManager = serviceProvider.GetRequiredService>(); var userManager = serviceProvider.GetRequiredService>(); var configuration = serviceProvider.GetRequiredService(); var context = serviceProvider.GetRequiredService(); await SeedIdentityAsync(roleManager, userManager, configuration); 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 SeedIdentityAsync(RoleManager roleManager, UserManager userManager, IConfiguration configuration) { var adminSettings = configuration.GetSection("IdentitySettings:DefaultAdmin").Get(); 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); } } } private static async Task SeedCurrenciesAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var currencies = new List { 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().AddRangeAsync(currencies); await context.SaveChangesAsync(); } private static async Task SeedCompanyAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var usdCurrency = await context.Set().FirstOrDefaultAsync(x => x.Code == "USD"); if (usdCurrency == null) return; var companies = new List { 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().AddRangeAsync(companies); await context.SaveChangesAsync(); } private static async Task SeedTaxAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var taxes = new List { 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().AddRangeAsync(taxes); await context.SaveChangesAsync(); } private static async Task SeedBranchAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var branches = new List { 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().AddRangeAsync(branches); await context.SaveChangesAsync(); } private static async Task SeedDepartmentAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var departments = new List { 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().AddRangeAsync(departments); await context.SaveChangesAsync(); } private static async Task SeedDesignationAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var designations = new List { 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().AddRangeAsync(designations); await context.SaveChangesAsync(); } private static async Task SeedIncomeAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var incomes = new List { 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().AddRangeAsync(incomes); await context.SaveChangesAsync(); } private static async Task SeedDeductionAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var deductions = new List { 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().AddRangeAsync(deductions); await context.SaveChangesAsync(); } private static async Task SeedGradeAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var grades = new List { 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().AddRangeAsync(grades); await context.SaveChangesAsync(); } private static async Task SeedEmployeeAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var hqBranch = await context.Set().FirstOrDefaultAsync(x => x.Code == "US-NYC"); var itDept = await context.Set().FirstOrDefaultAsync(x => x.CostCenter == "US-IT"); var managerDesig = await context.Set().FirstOrDefaultAsync(x => x.Code == "MGR-01"); var allGrades = await context.Set().ToListAsync(); var wfhStipend = await context.Set().FirstOrDefaultAsync(x => x.Code == "WFH"); var healthIns = await context.Set().FirstOrDefaultAsync(x => x.Code == "HLTH"); var retirement401k = await context.Set().FirstOrDefaultAsync(x => x.Code == "401K"); if (hqBranch == null || itDept == null || managerDesig == null || !allGrades.Any()) return; var random = new Random(); var employees = new List(); var empIncomes = new List(); var empDeductions = new List(); // 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().AddRangeAsync(employees); await context.Set().AddRangeAsync(empIncomes); await context.Set().AddRangeAsync(empDeductions); await context.SaveChangesAsync(); } private static async Task SeedLeaveCategoryAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var categories = new List { 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().AddRangeAsync(categories); await context.SaveChangesAsync(); } private static async Task SeedLeaveBalanceAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var employees = await context.Set().Take(15).ToListAsync(); var ptoLeave = await context.Set().FirstOrDefaultAsync(x => x.Code == "US-PTO"); if (!employees.Any() || ptoLeave == null) return; var balances = new List(); 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().AddRangeAsync(balances); await context.SaveChangesAsync(); } private static async Task SeedLeaveRequestAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var categories = await context.Set().ToListAsync(); var employees = await context.Set().ToListAsync(); var requests = new List(); 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().AddRangeAsync(requests); await context.SaveChangesAsync(); } private static async Task SeedEvaluationAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var allEmployees = await context.Set().ToListAsync(); if (allEmployees.Count < 5) return; var evaluations = new List(); 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().AddRangeAsync(evaluations); await context.SaveChangesAsync(); } private static async Task SeedAppraisalAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var employees = await context.Set().Skip(5).Take(15).ToListAsync(); var appraisals = new List(); 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().AddRangeAsync(appraisals); await context.SaveChangesAsync(); } private static async Task SeedPromotionAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var employees = await context.Set().Skip(2).Take(10).ToListAsync(); var promotions = new List(); 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().AddRangeAsync(promotions); await context.SaveChangesAsync(); } private static async Task SeedTransferAsync(AppDbContext context) { if (await context.Set().AnyAsync()) return; var employees = await context.Set().Take(10).ToListAsync(); var branches = await context.Set().ToListAsync(); var depts = await context.Set().ToListAsync(); var desigs = await context.Set().ToListAsync(); var transfers = new List(); 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().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(); var payrollDetails = new List(); var payrollComponents = new List(); 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(); } }