2026-01-23 20:03:24 +01:00
|
|
|
using System.Text.Json;
|
2026-01-12 22:10:57 +01:00
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
using PlanTempus.Application.Features.Localization.Services;
|
|
|
|
|
|
|
|
|
|
namespace PlanTempus.Application.Features.Employees.Components;
|
|
|
|
|
|
|
|
|
|
public class EmployeeDetailSalaryViewComponent : ViewComponent
|
|
|
|
|
{
|
|
|
|
|
private readonly ILocalizationService _localization;
|
2026-01-23 20:03:24 +01:00
|
|
|
private readonly IWebHostEnvironment _environment;
|
2026-01-12 22:10:57 +01:00
|
|
|
|
2026-01-23 20:03:24 +01:00
|
|
|
public EmployeeDetailSalaryViewComponent(ILocalizationService localization, IWebHostEnvironment environment)
|
2026-01-12 22:10:57 +01:00
|
|
|
{
|
|
|
|
|
_localization = localization;
|
2026-01-23 20:03:24 +01:00
|
|
|
_environment = environment;
|
2026-01-12 22:10:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IViewComponentResult Invoke(string key)
|
|
|
|
|
{
|
|
|
|
|
var employee = EmployeeDetailCatalog.Get(key);
|
2026-01-23 20:03:24 +01:00
|
|
|
var salaryData = LoadSalarySpecifications();
|
2026-01-12 22:10:57 +01:00
|
|
|
|
|
|
|
|
var model = new EmployeeDetailSalaryViewModel
|
|
|
|
|
{
|
2026-01-23 20:03:24 +01:00
|
|
|
// Salary specifications from JSON
|
|
|
|
|
Specifications = salaryData.Specifications,
|
2026-01-13 22:37:29 +01:00
|
|
|
// Data
|
2026-01-12 22:10:57 +01:00
|
|
|
BankAccount = employee.BankAccount,
|
|
|
|
|
TaxCard = employee.TaxCard,
|
|
|
|
|
HourlyRate = employee.HourlyRate,
|
|
|
|
|
MonthlyFixedSalary = employee.MonthlyFixedSalary,
|
2026-01-13 22:37:29 +01:00
|
|
|
|
|
|
|
|
// Rates
|
|
|
|
|
NormalRate = employee.NormalRate,
|
|
|
|
|
OvertimeRate = employee.OvertimeRate,
|
|
|
|
|
VacationRate = employee.VacationRate,
|
|
|
|
|
|
|
|
|
|
// Commission
|
|
|
|
|
MinimumPerHour = employee.MinimumPerHour,
|
|
|
|
|
ServiceCommission = employee.ServiceCommission,
|
|
|
|
|
ProductCommission = employee.ProductCommission,
|
|
|
|
|
|
|
|
|
|
// Supplements
|
|
|
|
|
WeekdaySupplement = employee.WeekdaySupplement,
|
|
|
|
|
SaturdaySupplement = employee.SaturdaySupplement,
|
|
|
|
|
SundaySupplement = employee.SundaySupplement,
|
|
|
|
|
|
|
|
|
|
// Labels
|
|
|
|
|
LabelRates = _localization.Get("employees.detail.salary.rates"),
|
|
|
|
|
LabelNormalRate = _localization.Get("employees.detail.salary.normalrate"),
|
|
|
|
|
LabelOvertimeRate = _localization.Get("employees.detail.salary.overtimerate"),
|
|
|
|
|
LabelVacationRate = _localization.Get("employees.detail.salary.vacationrate"),
|
|
|
|
|
LabelProvision = _localization.Get("employees.detail.salary.provision"),
|
|
|
|
|
LabelMinimumPerHour = _localization.Get("employees.detail.salary.minimumperhour"),
|
|
|
|
|
LabelServiceCommission = _localization.Get("employees.detail.salary.servicecommission"),
|
|
|
|
|
LabelProductCommission = _localization.Get("employees.detail.salary.productcommission"),
|
|
|
|
|
LabelSupplements = _localization.Get("employees.detail.salary.supplements"),
|
|
|
|
|
LabelWeekdaySupplement = _localization.Get("employees.detail.salary.weekdaysupplement"),
|
|
|
|
|
LabelSaturdaySupplement = _localization.Get("employees.detail.salary.saturdaysupplement"),
|
|
|
|
|
LabelSundaySupplement = _localization.Get("employees.detail.salary.sundaysupplement"),
|
|
|
|
|
LabelSalaryHistory = _localization.Get("employees.detail.salary.history"),
|
|
|
|
|
LabelPeriod = _localization.Get("employees.detail.salary.period"),
|
|
|
|
|
LabelGrossSalary = _localization.Get("employees.detail.salary.grosssalary"),
|
|
|
|
|
LabelView = _localization.Get("employees.detail.salary.view"),
|
|
|
|
|
LabelEdit = _localization.Get("common.edit"),
|
|
|
|
|
LabelRatesDrawerTitle = _localization.Get("employees.detail.salary.ratesdrawertitle"),
|
|
|
|
|
LabelBaseRates = _localization.Get("employees.detail.salary.baserates"),
|
|
|
|
|
LabelCourseRate = _localization.Get("employees.detail.salary.courserate"),
|
|
|
|
|
LabelTimeOffRate = _localization.Get("employees.detail.salary.timeoffrate"),
|
|
|
|
|
LabelPaidLeaveRate = _localization.Get("employees.detail.salary.paidleaverate"),
|
|
|
|
|
LabelOfficeRate = _localization.Get("employees.detail.salary.officerate"),
|
|
|
|
|
LabelChildSickRate = _localization.Get("employees.detail.salary.childsickrate"),
|
|
|
|
|
LabelChildHospitalRate = _localization.Get("employees.detail.salary.childhospitalrate"),
|
|
|
|
|
LabelMaternityRate = _localization.Get("employees.detail.salary.maternityrate"),
|
|
|
|
|
LabelWeekdaySupplementFull = _localization.Get("employees.detail.salary.weekdaysupplementfull"),
|
|
|
|
|
LabelSaturdaySupplementFull = _localization.Get("employees.detail.salary.saturdaysupplementfull"),
|
2026-01-12 22:10:57 +01:00
|
|
|
LabelCommission = _localization.Get("employees.detail.salary.commission"),
|
2026-01-13 22:37:29 +01:00
|
|
|
LabelProductCommissionFull = _localization.Get("employees.detail.salary.productcommissionfull"),
|
|
|
|
|
LabelServiceCommissionFull = _localization.Get("employees.detail.salary.servicecommissionfull"),
|
|
|
|
|
|
|
|
|
|
// Rate values (numeric only for drawer inputs)
|
|
|
|
|
NormalRateValue = employee.NormalRateValue,
|
|
|
|
|
OvertimeRateValue = employee.OvertimeRateValue,
|
|
|
|
|
CourseRateValue = employee.CourseRateValue,
|
|
|
|
|
TimeOffRateValue = employee.TimeOffRateValue,
|
|
|
|
|
PaidLeaveRateValue = employee.PaidLeaveRateValue,
|
|
|
|
|
VacationRateValue = employee.VacationRateValue,
|
|
|
|
|
OfficeRateValue = employee.OfficeRateValue,
|
|
|
|
|
ChildSickRateValue = employee.ChildSickRateValue,
|
|
|
|
|
ChildHospitalRateValue = employee.ChildHospitalRateValue,
|
|
|
|
|
MaternityRateValue = employee.MaternityRateValue,
|
|
|
|
|
WeekdaySupplementValue = employee.WeekdaySupplementValue,
|
|
|
|
|
SaturdaySupplementValue = employee.SaturdaySupplementValue,
|
|
|
|
|
SundaySupplementValue = employee.SundaySupplementValue,
|
|
|
|
|
ProductCommissionValue = employee.ProductCommissionValue,
|
|
|
|
|
ServiceCommissionValue = employee.ServiceCommissionValue,
|
|
|
|
|
|
2026-01-23 20:03:24 +01:00
|
|
|
// Labels for specifications
|
|
|
|
|
LabelSpecifications = _localization.Get("employees.detail.salary.specifications"),
|
|
|
|
|
LabelWeek = _localization.Get("employees.detail.salary.week"),
|
|
|
|
|
LabelNormalHours = _localization.Get("employees.detail.salary.normalhours"),
|
|
|
|
|
LabelOvertimeHours = _localization.Get("employees.detail.salary.overtimehours"),
|
|
|
|
|
LabelVacationDays = _localization.Get("employees.detail.salary.vacationdays"),
|
|
|
|
|
LabelServiceRevenue = _localization.Get("employees.detail.salary.servicerevenue"),
|
|
|
|
|
LabelProductRevenue = _localization.Get("employees.detail.salary.productrevenue"),
|
|
|
|
|
LabelMinimumThreshold = _localization.Get("employees.detail.salary.minimumthreshold"),
|
|
|
|
|
LabelTotal = _localization.Get("employees.detail.salary.total"),
|
|
|
|
|
LabelWeeklyNorm = _localization.Get("employees.detail.salary.weeklynorm"),
|
|
|
|
|
LabelOvertimeMultiplier = _localization.Get("employees.detail.salary.overtimemultiplier"),
|
|
|
|
|
LabelMinimum = _localization.Get("employees.detail.salary.minimum"),
|
|
|
|
|
|
|
|
|
|
// Mock salary history (kept for backwards compatibility)
|
2026-01-13 22:37:29 +01:00
|
|
|
SalaryHistory = new List<SalaryHistoryItem>
|
|
|
|
|
{
|
|
|
|
|
new() { Period = "Januar 2026", GrossSalary = "34.063,50 kr" },
|
|
|
|
|
new() { Period = "December 2025", GrossSalary = "31.845,00 kr" },
|
|
|
|
|
new() { Period = "November 2025", GrossSalary = "33.290,25 kr" },
|
|
|
|
|
new() { Period = "Oktober 2025", GrossSalary = "32.156,75 kr" },
|
|
|
|
|
new() { Period = "September 2025", GrossSalary = "34.520,00 kr" }
|
|
|
|
|
}
|
2026-01-12 22:10:57 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return View(model);
|
|
|
|
|
}
|
2026-01-23 20:03:24 +01:00
|
|
|
|
|
|
|
|
private SalarySpecificationRoot LoadSalarySpecifications()
|
|
|
|
|
{
|
|
|
|
|
var jsonPath = Path.Combine(_environment.ContentRootPath, "Features", "Employees", "Data", "salarySpecificationMock.json");
|
|
|
|
|
var json = System.IO.File.ReadAllText(jsonPath);
|
|
|
|
|
return JsonSerializer.Deserialize<SalarySpecificationRoot>(json, new JsonSerializerOptions
|
|
|
|
|
{
|
|
|
|
|
PropertyNameCaseInsensitive = true
|
|
|
|
|
})!;
|
|
|
|
|
}
|
2026-01-12 22:10:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class EmployeeDetailSalaryViewModel
|
|
|
|
|
{
|
2026-01-23 20:03:24 +01:00
|
|
|
// Salary Specifications (from JSON)
|
|
|
|
|
public List<SalarySpecificationDto> Specifications { get; init; } = new();
|
|
|
|
|
|
2026-01-13 22:37:29 +01:00
|
|
|
// Data
|
2026-01-12 22:10:57 +01:00
|
|
|
public required string BankAccount { get; init; }
|
|
|
|
|
public required string TaxCard { get; init; }
|
|
|
|
|
public required string HourlyRate { get; init; }
|
|
|
|
|
public required string MonthlyFixedSalary { get; init; }
|
2026-01-13 22:37:29 +01:00
|
|
|
|
|
|
|
|
// Rates
|
|
|
|
|
public required string NormalRate { get; init; }
|
|
|
|
|
public required string OvertimeRate { get; init; }
|
|
|
|
|
public required string VacationRate { get; init; }
|
|
|
|
|
|
|
|
|
|
// Commission
|
|
|
|
|
public required string MinimumPerHour { get; init; }
|
|
|
|
|
public required string ServiceCommission { get; init; }
|
|
|
|
|
public required string ProductCommission { get; init; }
|
|
|
|
|
|
|
|
|
|
// Supplements
|
|
|
|
|
public required string WeekdaySupplement { get; init; }
|
|
|
|
|
public required string SaturdaySupplement { get; init; }
|
|
|
|
|
public required string SundaySupplement { get; init; }
|
|
|
|
|
|
|
|
|
|
// Labels
|
|
|
|
|
public required string LabelRates { get; init; }
|
|
|
|
|
public required string LabelNormalRate { get; init; }
|
|
|
|
|
public required string LabelOvertimeRate { get; init; }
|
|
|
|
|
public required string LabelVacationRate { get; init; }
|
|
|
|
|
public required string LabelProvision { get; init; }
|
|
|
|
|
public required string LabelMinimumPerHour { get; init; }
|
|
|
|
|
public required string LabelServiceCommission { get; init; }
|
2026-01-12 22:10:57 +01:00
|
|
|
public required string LabelProductCommission { get; init; }
|
2026-01-13 22:37:29 +01:00
|
|
|
public required string LabelSupplements { get; init; }
|
|
|
|
|
public required string LabelWeekdaySupplement { get; init; }
|
|
|
|
|
public required string LabelSaturdaySupplement { get; init; }
|
|
|
|
|
public required string LabelSundaySupplement { get; init; }
|
|
|
|
|
public required string LabelSalaryHistory { get; init; }
|
|
|
|
|
public required string LabelPeriod { get; init; }
|
|
|
|
|
public required string LabelGrossSalary { get; init; }
|
|
|
|
|
public required string LabelView { get; init; }
|
|
|
|
|
public required string LabelEdit { get; init; }
|
|
|
|
|
public required string LabelRatesDrawerTitle { get; init; }
|
|
|
|
|
public required string LabelBaseRates { get; init; }
|
|
|
|
|
public required string LabelCourseRate { get; init; }
|
|
|
|
|
public required string LabelTimeOffRate { get; init; }
|
|
|
|
|
public required string LabelPaidLeaveRate { get; init; }
|
|
|
|
|
public required string LabelOfficeRate { get; init; }
|
|
|
|
|
public required string LabelChildSickRate { get; init; }
|
|
|
|
|
public required string LabelChildHospitalRate { get; init; }
|
|
|
|
|
public required string LabelMaternityRate { get; init; }
|
|
|
|
|
public required string LabelWeekdaySupplementFull { get; init; }
|
|
|
|
|
public required string LabelSaturdaySupplementFull { get; init; }
|
|
|
|
|
public required string LabelCommission { get; init; }
|
|
|
|
|
public required string LabelProductCommissionFull { get; init; }
|
|
|
|
|
public required string LabelServiceCommissionFull { get; init; }
|
|
|
|
|
|
2026-01-23 20:03:24 +01:00
|
|
|
// Labels for specifications accordion
|
|
|
|
|
public required string LabelSpecifications { get; init; }
|
|
|
|
|
public required string LabelWeek { get; init; }
|
|
|
|
|
public required string LabelNormalHours { get; init; }
|
|
|
|
|
public required string LabelOvertimeHours { get; init; }
|
|
|
|
|
public required string LabelVacationDays { get; init; }
|
|
|
|
|
public required string LabelServiceRevenue { get; init; }
|
|
|
|
|
public required string LabelProductRevenue { get; init; }
|
|
|
|
|
public required string LabelMinimumThreshold { get; init; }
|
|
|
|
|
public required string LabelTotal { get; init; }
|
|
|
|
|
public required string LabelWeeklyNorm { get; init; }
|
|
|
|
|
public required string LabelOvertimeMultiplier { get; init; }
|
|
|
|
|
public required string LabelMinimum { get; init; }
|
|
|
|
|
|
2026-01-13 22:37:29 +01:00
|
|
|
// Rate values (for drawer inputs)
|
|
|
|
|
public required string NormalRateValue { get; init; }
|
|
|
|
|
public required string OvertimeRateValue { get; init; }
|
|
|
|
|
public required string CourseRateValue { get; init; }
|
|
|
|
|
public required string TimeOffRateValue { get; init; }
|
|
|
|
|
public required string PaidLeaveRateValue { get; init; }
|
|
|
|
|
public required string VacationRateValue { get; init; }
|
|
|
|
|
public required string OfficeRateValue { get; init; }
|
|
|
|
|
public required string ChildSickRateValue { get; init; }
|
|
|
|
|
public required string ChildHospitalRateValue { get; init; }
|
|
|
|
|
public required string MaternityRateValue { get; init; }
|
|
|
|
|
public required string WeekdaySupplementValue { get; init; }
|
|
|
|
|
public required string SaturdaySupplementValue { get; init; }
|
|
|
|
|
public required string SundaySupplementValue { get; init; }
|
|
|
|
|
public required string ProductCommissionValue { get; init; }
|
|
|
|
|
public required string ServiceCommissionValue { get; init; }
|
|
|
|
|
|
|
|
|
|
// Salary History (mock data)
|
|
|
|
|
public List<SalaryHistoryItem> SalaryHistory { get; init; } = new();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class SalaryHistoryItem
|
|
|
|
|
{
|
|
|
|
|
public required string Period { get; init; }
|
|
|
|
|
public required string GrossSalary { get; init; }
|
2026-01-12 22:10:57 +01:00
|
|
|
}
|
2026-01-23 20:03:24 +01:00
|
|
|
|
|
|
|
|
// DTOs for salary specification JSON
|
|
|
|
|
public class SalarySpecificationRoot
|
|
|
|
|
{
|
|
|
|
|
public List<SalarySpecificationDto> Specifications { get; init; } = new();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class SalarySpecificationDto
|
|
|
|
|
{
|
|
|
|
|
public required string Period { get; init; }
|
|
|
|
|
public required string PeriodKey { get; init; }
|
|
|
|
|
public decimal GrossSalary { get; init; }
|
|
|
|
|
public decimal BasePay { get; init; }
|
|
|
|
|
public decimal OvertimePay { get; init; }
|
|
|
|
|
public decimal ServiceCommission { get; init; }
|
|
|
|
|
public decimal ProductCommission { get; init; }
|
|
|
|
|
public SalaryConfigDto Config { get; init; } = new();
|
|
|
|
|
public List<SalaryWeekDto> Weeks { get; init; } = new();
|
|
|
|
|
|
|
|
|
|
// Formatted values for display
|
|
|
|
|
public string GrossSalaryFormatted => GrossSalary.ToString("N2", System.Globalization.CultureInfo.GetCultureInfo("da-DK")) + " kr";
|
|
|
|
|
public string BasePayFormatted => BasePay.ToString("N2", System.Globalization.CultureInfo.GetCultureInfo("da-DK")) + " kr";
|
|
|
|
|
public string OvertimePayFormatted => OvertimePay.ToString("N2", System.Globalization.CultureInfo.GetCultureInfo("da-DK")) + " kr";
|
|
|
|
|
public string TotalCommission => (ServiceCommission + ProductCommission).ToString("N2", System.Globalization.CultureInfo.GetCultureInfo("da-DK")) + " kr";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class SalaryConfigDto
|
|
|
|
|
{
|
|
|
|
|
public decimal HourlyRate { get; init; }
|
|
|
|
|
public int WeeklyHours { get; init; }
|
|
|
|
|
public decimal OvertimeMultiplier { get; init; }
|
|
|
|
|
public decimal MinimumPerHour { get; init; }
|
|
|
|
|
public int ServiceCommissionPct { get; init; }
|
|
|
|
|
public int ProductCommissionPct { get; init; }
|
|
|
|
|
|
|
|
|
|
// Formatted values
|
|
|
|
|
public string HourlyRateFormatted => HourlyRate.ToString("N0", System.Globalization.CultureInfo.GetCultureInfo("da-DK")) + " kr";
|
|
|
|
|
public string WeeklyHoursFormatted => WeeklyHours + "t/uge";
|
|
|
|
|
public string OvertimeFormatted => "+" + Math.Round((OvertimeMultiplier - 1) * 100) + "%";
|
|
|
|
|
public string MinimumFormatted => MinimumPerHour.ToString("N0", System.Globalization.CultureInfo.GetCultureInfo("da-DK")) + " kr/time";
|
|
|
|
|
public string CommissionFormatted => ServiceCommissionPct + "% services · " + ProductCommissionPct + "% produkter";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class SalaryWeekDto
|
|
|
|
|
{
|
|
|
|
|
public int WeekNumber { get; init; }
|
|
|
|
|
public int NormalHours { get; init; }
|
|
|
|
|
public int OvertimeHours { get; init; }
|
|
|
|
|
public int VacationDays { get; init; }
|
|
|
|
|
public decimal ServiceRevenue { get; init; }
|
|
|
|
|
public decimal ProductRevenue { get; init; }
|
|
|
|
|
public decimal MinimumThreshold { get; init; }
|
|
|
|
|
public decimal Commission { get; init; }
|
|
|
|
|
public decimal TotalPay { get; init; }
|
|
|
|
|
|
|
|
|
|
// Formatted values
|
|
|
|
|
public string NormalHoursFormatted => NormalHours + "t";
|
|
|
|
|
public string OvertimeHoursFormatted => OvertimeHours + "t";
|
|
|
|
|
public string VacationDaysFormatted => VacationDays + " dg";
|
|
|
|
|
public string ServiceRevenueFormatted => ServiceRevenue.ToString("N0", System.Globalization.CultureInfo.GetCultureInfo("da-DK")) + " kr";
|
|
|
|
|
public string ProductRevenueFormatted => ProductRevenue.ToString("N0", System.Globalization.CultureInfo.GetCultureInfo("da-DK")) + " kr";
|
|
|
|
|
public string MinimumThresholdFormatted => MinimumThreshold.ToString("N0", System.Globalization.CultureInfo.GetCultureInfo("da-DK")) + " kr";
|
|
|
|
|
public string CommissionFormatted => Commission.ToString("N2", System.Globalization.CultureInfo.GetCultureInfo("da-DK")) + " kr";
|
|
|
|
|
public string TotalPayFormatted => TotalPay.ToString("N2", System.Globalization.CultureInfo.GetCultureInfo("da-DK")) + " kr";
|
|
|
|
|
public bool HasOvertime => OvertimeHours > 0;
|
|
|
|
|
public bool HasCommission => Commission > 0;
|
|
|
|
|
}
|