142 lines
5.1 KiB
C#
142 lines
5.1 KiB
C#
using Indotalent.ConfigBackEnd.Exceptions;
|
|
using Indotalent.ConfigBackEnd.Extensions;
|
|
using Indotalent.Infrastructure.Database;
|
|
using MediatR;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace Indotalent.Features.Payroll.Payrolls.Cqrs;
|
|
|
|
public class CreatePayrollProcessRequest
|
|
{
|
|
public string? PeriodName { get; set; }
|
|
public DateTime? FromDate { get; set; }
|
|
public DateTime? ToDate { get; set; }
|
|
public string? Description { get; set; }
|
|
}
|
|
|
|
public class CreatePayrollProcessResponse
|
|
{
|
|
public string? Id { get; set; }
|
|
public string? AutoNumber { get; set; }
|
|
}
|
|
|
|
public record CreatePayrollProcessCommand(CreatePayrollProcessRequest Data) : IRequest<CreatePayrollProcessResponse>;
|
|
|
|
public class CreatePayrollProcessHandler : IRequestHandler<CreatePayrollProcessCommand, CreatePayrollProcessResponse>
|
|
{
|
|
private readonly AppDbContext _context;
|
|
|
|
public CreatePayrollProcessHandler(AppDbContext context) => _context = context;
|
|
|
|
public async Task<CreatePayrollProcessResponse> Handle(CreatePayrollProcessCommand request, CancellationToken cancellationToken)
|
|
{
|
|
var isExists = await _context.PayrollProcess
|
|
.AnyAsync(x => x.PeriodName == request.Data.PeriodName, cancellationToken);
|
|
|
|
if (isExists)
|
|
{
|
|
throw new AlreadyExistsException("Payroll Period", request.Data.PeriodName ?? string.Empty);
|
|
}
|
|
|
|
var entityName = nameof(Data.Entities.PayrollProcess);
|
|
|
|
var autoNo = await _context.GenerateAutoNumberAsync(
|
|
entityName: entityName,
|
|
prefixTemplate: $"PAY/{request.Data.FromDate?.ToString("yyyyMM") ?? DateTime.Now.ToString("yyyyMM")}/",
|
|
ct: cancellationToken
|
|
);
|
|
|
|
var payrollProcess = new Data.Entities.PayrollProcess
|
|
{
|
|
AutoNumber = autoNo,
|
|
PeriodName = request.Data.PeriodName,
|
|
FromDate = request.Data.FromDate ?? DateTime.Now,
|
|
ToDate = request.Data.ToDate ?? DateTime.Now,
|
|
Description = request.Data.Description,
|
|
Status = "Draft",
|
|
ProcessedBy = "System Admin",
|
|
ProcessedAt = DateTime.Now
|
|
};
|
|
|
|
var employees = await _context.Employee
|
|
.Include(x => x.EmployeeIncome)
|
|
.Include(x => x.EmployeeDeduction)
|
|
.Where(x => x.EmployeeStatus == "Active")
|
|
.ToListAsync(cancellationToken);
|
|
|
|
decimal grandBasicSalary = 0;
|
|
decimal grandTotalIncome = 0;
|
|
decimal grandTotalDeduction = 0;
|
|
|
|
foreach (var emp in employees)
|
|
{
|
|
var totalIncome = emp.EmployeeIncome?.Sum(x => x.Amount) ?? 0m;
|
|
var totalDeduction = emp.EmployeeDeduction?.Sum(x => x.Amount) ?? 0m;
|
|
var takeHomePay = emp.BasicSalary + totalIncome - totalDeduction;
|
|
|
|
var detail = new Data.Entities.PayrollDetail
|
|
{
|
|
PayrollProcess = payrollProcess,
|
|
EmployeeId = emp.Id,
|
|
EmployeeCode = emp.Code,
|
|
EmployeeName = $"{emp.FirstName} {emp.LastName}",
|
|
BasicSalary = emp.BasicSalary,
|
|
TotalIncome = totalIncome,
|
|
TotalDeduction = totalDeduction,
|
|
TakeHomePay = takeHomePay
|
|
};
|
|
|
|
if (emp.EmployeeIncome != null)
|
|
{
|
|
foreach (var inc in emp.EmployeeIncome)
|
|
{
|
|
detail.Components.Add(new Data.Entities.PayrollComponent
|
|
{
|
|
PayrollDetail = detail,
|
|
ComponentName = "Income Component",
|
|
ComponentType = "Income",
|
|
Amount = inc.Amount,
|
|
Description = inc.Description
|
|
});
|
|
}
|
|
}
|
|
|
|
if (emp.EmployeeDeduction != null)
|
|
{
|
|
foreach (var ded in emp.EmployeeDeduction)
|
|
{
|
|
detail.Components.Add(new Data.Entities.PayrollComponent
|
|
{
|
|
PayrollDetail = detail,
|
|
ComponentName = "Deduction Component",
|
|
ComponentType = "Deduction",
|
|
Amount = ded.Amount,
|
|
Description = ded.Description
|
|
});
|
|
}
|
|
}
|
|
|
|
grandBasicSalary += detail.BasicSalary;
|
|
grandTotalIncome += totalIncome;
|
|
grandTotalDeduction += totalDeduction;
|
|
|
|
_context.PayrollDetail.Add(detail);
|
|
}
|
|
|
|
payrollProcess.TotalEmployees = employees.Count;
|
|
payrollProcess.TotalBasicSalary = grandBasicSalary;
|
|
payrollProcess.TotalIncome = grandTotalIncome;
|
|
payrollProcess.TotalDeduction = grandTotalDeduction;
|
|
payrollProcess.TotalGross = grandBasicSalary + grandTotalIncome;
|
|
payrollProcess.TotalTakeHomePay = payrollProcess.TotalGross - grandTotalDeduction;
|
|
|
|
_context.PayrollProcess.Add(payrollProcess);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
return new CreatePayrollProcessResponse
|
|
{
|
|
Id = payrollProcess.Id,
|
|
AutoNumber = payrollProcess.AutoNumber
|
|
};
|
|
}
|
|
} |