293 lines
12 KiB
C#
293 lines
12 KiB
C#
using LCU.API.Internal.Operations.IncentiveApi.Services.Payout;
|
|
using LCU.API.Internal.Operations.IncentiveApi.Models.Dayforce;
|
|
using LCU.API.Internal.Operations.IncentiveApiLib.Services;
|
|
using LCU.API.Internal.Operations.IncentiveApiLib.Repositories;
|
|
using LCU.Library.Internal.IncentiveApiModels.Entities;
|
|
using LCU.Library.Internal.IncentiveApiModels.Results;
|
|
using LCU.API.Internal.Operations.IncentiveApi.Services;
|
|
using LCU.API.Internal.Operations.IncentiveApi.Services.MicroApiServices;
|
|
using LCU.API.Internal.Operations.IncentiveApi.Configuration;
|
|
using LCU.Library.Internal.IncentiveApiModels.Requests;
|
|
using LCU.Library.Internal.ApiResponse.Services;
|
|
using ProcessResult = LCU.Library.Internal.IncentiveApiModels.Results.ProcessResult;
|
|
|
|
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Dayforce;
|
|
|
|
public class DayForceSyncService : IDayForceSyncService
|
|
{
|
|
private readonly IUnitOfWork _unitOfWork;
|
|
private readonly IUserService _userService;
|
|
private readonly INotificationApiService _notificationService;
|
|
private readonly IPayoutService _payoutService;
|
|
private readonly IDayForceClientService _dayForceClientService;
|
|
private readonly ISettingsService _settingsService;
|
|
private readonly DayForceConfiguration _dayForceConfig;
|
|
private readonly ProcessResult _dayforceSyncProcessResult;
|
|
|
|
public DayForceSyncService(
|
|
IUnitOfWork unitOfWork,
|
|
IUserService userService,
|
|
INotificationApiService notificationService,
|
|
IPayoutService payoutService,
|
|
IDayForceClientService dayForceClientService,
|
|
ISettingsService settingsService,
|
|
DayForceConfiguration dayForceConfig
|
|
)
|
|
{
|
|
_unitOfWork = unitOfWork;
|
|
_userService = userService;
|
|
_notificationService = notificationService;
|
|
_payoutService = payoutService;
|
|
_dayForceClientService = dayForceClientService;
|
|
_settingsService = settingsService;
|
|
_dayForceConfig = dayForceConfig;
|
|
_dayforceSyncProcessResult = new ProcessResult();
|
|
}
|
|
|
|
public async Task SyncDayForceUsers(DayforceProcessRequest request)
|
|
{
|
|
try
|
|
{
|
|
Log.Information("Starting Dayforce Sync Process for Active Users.");
|
|
|
|
if (request.MissingRoleNotification == null)
|
|
{
|
|
request.MissingRoleNotification = _dayForceConfig.DayForceManualReportRecipients;
|
|
}
|
|
|
|
if (request.TerminatedEmployeeNotification == null)
|
|
{
|
|
request.TerminatedEmployeeNotification = _dayForceConfig.DayForceManualReportRecipients;
|
|
}
|
|
|
|
var activeUsersResult = await SyncActiveDayForceUsers(request.MissingRoleNotification);
|
|
Log.Information("Completed Dayforce Sync Process for Active Users.");
|
|
_dayforceSyncProcessResult.MessageStack.Add($"Dayforce Sync Process for Active Users complete with {activeUsersResult.Count()}");
|
|
|
|
Log.Information("Starting Dayforce Sync Process for Terminated Users.");
|
|
var terminatedUsersResult = await SyncTerminatedDayForceUsers(request.TerminatedEmployeeNotification);
|
|
Log.Information("Completed Dayforce Sync Process for Terminated Users.");
|
|
|
|
_dayforceSyncProcessResult.MessageStack.Add($"Dayforce Sync Process for Terminated Users complete with {terminatedUsersResult.Count()}");
|
|
await SafeQueueReturnResponse.TryQueueResponse(request, _dayforceSyncProcessResult.Success, _dayforceSyncProcessResult.MessageStack, nameof(DayForceSyncService));
|
|
}
|
|
catch ( Exception exception )
|
|
{
|
|
Log.Fatal(exception, "There was an Unhandled error Executing Dayforce Sync Process");
|
|
var message = $"There was an issue with handling the Dayforce Sync Service Process Exception Message: {exception.Message}.";
|
|
_dayforceSyncProcessResult.MessageStack.Add(message);
|
|
_dayforceSyncProcessResult.Success = false;
|
|
await SafeQueueReturnResponse.TryQueueResponse(request, _dayforceSyncProcessResult.Success, _dayforceSyncProcessResult.MessageStack, nameof(DayForceSyncService));
|
|
}
|
|
}
|
|
|
|
public async Task<IReadOnlyCollection<ActiveEmployeeReceipt>> SyncActiveDayForceUsers(List<string> recipients)
|
|
{
|
|
var report = await _dayForceClientService.GetReportData(_dayForceConfig.DayForceActiveUserReport);
|
|
var results = new List<ActiveEmployeeReceipt>();
|
|
|
|
if (report.Rows == null)
|
|
{
|
|
throw new Exception("Dayforce returned invalid active report");
|
|
}
|
|
|
|
foreach (var reportRow in report.Rows)
|
|
{
|
|
var receipt = new ActiveEmployeeReceipt(reportRow);
|
|
results.Add(receipt);
|
|
try
|
|
{
|
|
var employee = new ActiveEmployeeResult(reportRow);
|
|
receipt.EmployeeRow = employee;
|
|
|
|
if (!employee.CanProcess())
|
|
{
|
|
Log.Error("Cannot process dayforce employee. {reportRow}", reportRow.Values);
|
|
receipt.Status = ActiveEmployeeReceiptStatus.MISSING_DATA;
|
|
continue;
|
|
}
|
|
|
|
var appUser = await _userService.SyncDayForceEmployee(employee);
|
|
receipt.AppUser = appUser;
|
|
receipt.Status = ActiveEmployeeReceiptStatus.SUCCESS;
|
|
|
|
if (appUser.Departments.Any(x => x.Role == Role.MISSING_ROLE))
|
|
{
|
|
receipt.Status = ActiveEmployeeReceiptStatus.MISSING_ROLE;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Failed to process dayforce employee. {reportRow}", reportRow.Values);
|
|
receipt.Status = ActiveEmployeeReceiptStatus.EXCEPTION;
|
|
}
|
|
}
|
|
|
|
var nonExistentRoleAssignments = results
|
|
.Where(x => x.Status == ActiveEmployeeReceiptStatus.MISSING_ROLE)
|
|
.Select(x => x.AppUser)
|
|
.ToList();
|
|
|
|
if (nonExistentRoleAssignments.Any())
|
|
{
|
|
var newRoleMappings = nonExistentRoleAssignments.Select(x => x.BaseRole).ToList().Distinct();
|
|
await _notificationService.SendMissingRoleNotification(nonExistentRoleAssignments, recipients);
|
|
await _settingsService.SaveNewUnknownRoleMappingRangeAsync(newRoleMappings);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
public async Task<IReadOnlyCollection<TerminatedEmployeeReceipt>> SyncTerminatedDayForceUsers(List<string> recipients)
|
|
{
|
|
var report = await _dayForceClientService.GetReportData(_dayForceConfig.DayForceTerminatedUserReport);
|
|
var terminated = new List<TerminatedEmployeeReceipt>();
|
|
|
|
if (report.Rows == null)
|
|
{
|
|
throw new Exception("Dayforce returned invalid termination report");
|
|
}
|
|
|
|
foreach (var reportRow in report.Rows)
|
|
{
|
|
try
|
|
{
|
|
var employee = new TerminatedEmployeeResult(reportRow);
|
|
var user = await _userService.TerminateDayForceEmployee(employee);
|
|
|
|
if (user != null)
|
|
{
|
|
var manager = await _userService.FindManager(user);
|
|
var receipt = await _payoutService.CreateTerminatedEmployeePayouts(user, manager);
|
|
terminated.Add(receipt);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Failed to term dayforce employee. {reportRow}", reportRow.Values);
|
|
}
|
|
}
|
|
|
|
if (terminated.Any())
|
|
{
|
|
await _notificationService.SendTerminatedEmployeeNotification(terminated, recipients);
|
|
}
|
|
|
|
return terminated;
|
|
}
|
|
|
|
public async Task<EmployeeDetailsUpdateResult> UpdateEmployeeDetails(EmployeeDetailsUpdate employeeDetailsUpdate)
|
|
{
|
|
var currentAppUser = await _userService.GetUserByAdEmailAsync(employeeDetailsUpdate.OldEmail);
|
|
if (currentAppUser == null)
|
|
{
|
|
return new EmployeeDetailsUpdateResult
|
|
{
|
|
UpdateMessage = $"Employee Details Update Failed, No Current Users Returned From Database"
|
|
};
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(employeeDetailsUpdate.InvalidUpdateData()))
|
|
{
|
|
return new EmployeeDetailsUpdateResult
|
|
{
|
|
AppUser = currentAppUser,
|
|
UpdateMessage = $"Employee Details Update Failed, {employeeDetailsUpdate.InvalidUpdateData()}"
|
|
};
|
|
}
|
|
|
|
var existingUserForNewEmail = await _userService.GetActiveUserByAdEmailAsync(employeeDetailsUpdate.NewEmail);
|
|
if (existingUserForNewEmail != null
|
|
&& !existingUserForNewEmail.AdEmail.Equals(currentAppUser.AdEmail, StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
return new EmployeeDetailsUpdateResult
|
|
{
|
|
AppUser = currentAppUser,
|
|
UpdateMessage = $"Employee Details Update Failed, Another Active User Already Exists With Email: {employeeDetailsUpdate.NewEmail}"
|
|
};
|
|
}
|
|
|
|
var existingUserForNewEmployeeId = await _userService.GetActiveUserByEmployeeIdAsync(employeeDetailsUpdate.NewEmployeeId);
|
|
if (existingUserForNewEmployeeId != null
|
|
&& !existingUserForNewEmployeeId.EmployeeId.Equals(currentAppUser.EmployeeId, StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
return new EmployeeDetailsUpdateResult
|
|
{
|
|
AppUser = currentAppUser,
|
|
UpdateMessage = $"Employee Details Update Failed, Another Active User Already Exists With EmployeeId: {employeeDetailsUpdate.NewEmployeeId}"
|
|
};
|
|
}
|
|
|
|
var hcmUsersMatched = await MatchingHcmUserCount(employeeDetailsUpdate);
|
|
if (hcmUsersMatched != 1)
|
|
{
|
|
return new EmployeeDetailsUpdateResult
|
|
{
|
|
AppUser = currentAppUser,
|
|
UpdateMessage = $"Employee Details Update Failed, {hcmUsersMatched} Users Returned From HCM System Matching New Details"
|
|
};
|
|
}
|
|
|
|
return await _userService.UpdateEmployeeDetails(employeeDetailsUpdate);
|
|
}
|
|
|
|
public async Task<IReadOnlyCollection<ActiveEmployeeResult>> GetMatchingHcmUsers(string email = "", string employeeId = "", string fullName = "")
|
|
{
|
|
if (
|
|
string.IsNullOrWhiteSpace(email)
|
|
&& string.IsNullOrWhiteSpace(employeeId)
|
|
&& string.IsNullOrWhiteSpace(fullName)
|
|
)
|
|
{
|
|
return new List<ActiveEmployeeResult>();
|
|
}
|
|
|
|
var dayForceUsers = await GetAllHcmUsers();
|
|
return dayForceUsers.Where(x =>
|
|
x.EmployeeNumber.ToString().Equals(employeeId, StringComparison.InvariantCultureIgnoreCase)
|
|
|| x.DisplayName.ToString().Equals(fullName, StringComparison.InvariantCultureIgnoreCase)
|
|
|| x.LoginName.ToString().Equals(email, StringComparison.InvariantCultureIgnoreCase)
|
|
)
|
|
.ToList();
|
|
}
|
|
|
|
private async Task<IReadOnlyCollection<ActiveEmployeeResult>> GetAllHcmUsers()
|
|
{
|
|
var report = await _dayForceClientService.GetReportData(_dayForceConfig.DayForceActiveUserReport);
|
|
var results = new List<ActiveEmployeeResult>();
|
|
|
|
if (report.Rows == null)
|
|
{
|
|
throw new Exception("Dayforce returned invalid active report");
|
|
}
|
|
|
|
foreach (var reportRow in report.Rows)
|
|
{
|
|
try
|
|
{
|
|
var employee = new ActiveEmployeeResult(reportRow);
|
|
results.Add(employee);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Failed to parse dayforce employee. {reportRow}", reportRow.Values);
|
|
}
|
|
}
|
|
|
|
return results.Where(x => x.CanProcess()).OrderBy(x => x.DisplayName).ToList();
|
|
}
|
|
|
|
private async Task<int> MatchingHcmUserCount(EmployeeDetailsUpdate employeeDetailsUpdate)
|
|
{
|
|
var dayForceUsers = await GetAllHcmUsers();
|
|
var matchingDayforceUsers = dayForceUsers.Where(x =>
|
|
x.EmployeeNumber.ToString().Equals(employeeDetailsUpdate.NewEmployeeId, StringComparison.InvariantCultureIgnoreCase)
|
|
&& x.DisplayName.ToString().Equals(employeeDetailsUpdate.NewFullName, StringComparison.InvariantCultureIgnoreCase)
|
|
&& x.LoginName.ToString().Equals(employeeDetailsUpdate.NewEmail, StringComparison.InvariantCultureIgnoreCase)
|
|
)
|
|
.ToList();
|
|
|
|
return matchingDayforceUsers.Count;
|
|
}
|
|
}
|