Adding
This commit is contained in:
+78
@@ -0,0 +1,78 @@
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Configuration;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Dayforce;
|
||||
using System.Text;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Dayforce;
|
||||
|
||||
public class DayForceClientService : IDayForceClientService
|
||||
{
|
||||
private readonly DayForceConfiguration _dayForceConfig;
|
||||
private readonly Uri _baseUri;
|
||||
|
||||
public DayForceClientService(DayForceConfiguration dayForceConfig)
|
||||
{
|
||||
_dayForceConfig = dayForceConfig;
|
||||
_baseUri = new Uri(_dayForceConfig.Url + "/" +
|
||||
_dayForceConfig.DayForceClientName + "/" +
|
||||
_dayForceConfig.DayForceApiVersion);
|
||||
}
|
||||
|
||||
public async Task<Report> GetReportData(string reportXRefCode)
|
||||
{
|
||||
var url = _baseUri.ToString() + "/Reports/" + reportXRefCode;
|
||||
var response = await GetHttpResponseAsync(url, true);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var jsonString = await response.Content.ReadAsStringAsync();
|
||||
var payload = JsonConvert.DeserializeObject<Payload<Report>>(jsonString);
|
||||
return payload.Data;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error Deserializing Dayforce Report");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("Bad Status Code retrieving report data from Dayforce {0}", response.ToString());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<HttpResponseMessage> GetHttpResponseAsync(string apiUrl, bool attemptRedirect = false)
|
||||
{
|
||||
var client = TrustingHttpClient.GetClient(apiUrl);
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, apiUrl);
|
||||
request.Headers.Authorization = CreateBasicAuthorizationHeader(request,
|
||||
_dayForceConfig.DayForceUsername,
|
||||
_dayForceConfig.DayForcePassword);
|
||||
|
||||
var response = await client.SendAsync(request);
|
||||
|
||||
if (attemptRedirect)
|
||||
{
|
||||
response = await GetHttpResponseAsync(response.RequestMessage.RequestUri.ToString(), false);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public AuthenticationHeaderValue CreateBasicAuthorizationHeader(HttpRequestMessage request, string userName,
|
||||
string password)
|
||||
{
|
||||
if (!(string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password)))
|
||||
{
|
||||
return new AuthenticationHeaderValue(
|
||||
"Basic", Convert.ToBase64String(
|
||||
Encoding.UTF8.GetBytes(userName + ":" + password)));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
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.MicroApiServices;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Configuration;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Requests;
|
||||
using LCU.Library.Internal.ApiResponse.Services;
|
||||
using LCU.Library.Internal.Exceptions;
|
||||
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 QueueReturnResponse.QueueResponse(request, _dayforceSyncProcessResult.Success, _dayforceSyncProcessResult.MessageStack);
|
||||
}
|
||||
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 QueueReturnResponse.QueueResponse(request, _dayforceSyncProcessResult.Success, _dayforceSyncProcessResult.MessageStack);
|
||||
throw new ServiceException(message);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Dayforce;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Dayforce;
|
||||
|
||||
public interface IDayForceClientService
|
||||
{
|
||||
Task<Report> GetReportData(string reportXRefCode);
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
using LCU.API.Internal.Operations.IncentiveApi.Models.Dayforce;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Requests;
|
||||
using LCU.Library.Internal.IncentiveApiModels.Results;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Dayforce;
|
||||
|
||||
public interface IDayForceSyncService
|
||||
{
|
||||
Task SyncDayForceUsers(DayforceProcessRequest request);
|
||||
Task<IReadOnlyCollection<ActiveEmployeeReceipt>> SyncActiveDayForceUsers(List<string> recipients);
|
||||
Task<IReadOnlyCollection<TerminatedEmployeeReceipt>> SyncTerminatedDayForceUsers(List<string> recipients);
|
||||
Task<IReadOnlyCollection<ActiveEmployeeResult>> GetMatchingHcmUsers(string email = "", string employeeId = "", string fullName = "");
|
||||
Task<EmployeeDetailsUpdateResult> UpdateEmployeeDetails(EmployeeDetailsUpdate employeeDetailsUpdate);
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
using System.Net.Http;
|
||||
|
||||
namespace LCU.API.Internal.Operations.IncentiveApi.Services.Dayforce;
|
||||
|
||||
public static class TrustingHttpClient
|
||||
{
|
||||
public static HttpClient GetClient(string endPoint)
|
||||
{
|
||||
var handler = new HttpClientHandler
|
||||
{
|
||||
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 |
|
||||
System.Security.Authentication.SslProtocols.Tls11 |
|
||||
System.Security.Authentication.SslProtocols.Tls,
|
||||
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
|
||||
};
|
||||
var httpClient = new HttpClient(handler)
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(300),
|
||||
BaseAddress = new Uri(endPoint)
|
||||
};
|
||||
return httpClient;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user