Refactor employee name handling to utilize workfeed_employee_name_formatter for improved name resolution and fallback logic
This commit is contained in:
@@ -8,6 +8,7 @@ use classes\response;
|
||||
use classes\router;
|
||||
use classes\weatherapi;
|
||||
use classes\workfeed;
|
||||
use classes\workfeed_employee_name_formatter;
|
||||
use classes\workfeed_shift_time_resolver;
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
@@ -1484,14 +1485,14 @@ class moduleWeatherAPIRoute
|
||||
return null;
|
||||
}
|
||||
|
||||
private function normalizeDepartmentName(string $name): string
|
||||
private static function normalizeDepartmentName(string $name): string
|
||||
{
|
||||
$collapsed = preg_replace('/\s+/', ' ', trim($name));
|
||||
|
||||
return strtolower($collapsed ?? trim($name));
|
||||
}
|
||||
|
||||
private function normalizeWorkfeedCollection(array|object $payload): array
|
||||
private static function normalizeWorkfeedCollection(array|object $payload): array
|
||||
{
|
||||
if (is_array($payload)) {
|
||||
return $payload;
|
||||
@@ -1514,7 +1515,7 @@ class moduleWeatherAPIRoute
|
||||
return [];
|
||||
}
|
||||
|
||||
private function normalizeWorkfeedRecord(mixed $record): array
|
||||
private static function normalizeWorkfeedRecord(mixed $record): array
|
||||
{
|
||||
if (is_array($record)) {
|
||||
return $record;
|
||||
@@ -1526,7 +1527,7 @@ class moduleWeatherAPIRoute
|
||||
return [];
|
||||
}
|
||||
|
||||
private function extractWorkfeedDepartmentId(mixed $shift): ?string
|
||||
private static function extractWorkfeedDepartmentId(mixed $shift): ?string
|
||||
{
|
||||
$record = self::normalizeWorkfeedRecord($shift);
|
||||
|
||||
@@ -1545,7 +1546,7 @@ class moduleWeatherAPIRoute
|
||||
return $normalized === '' ? null : $normalized;
|
||||
}
|
||||
|
||||
private function parseDateTimeValue(mixed $value): ?DateTime
|
||||
private static function parseDateTimeValue(mixed $value): ?DateTime
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$normalized = trim($value);
|
||||
@@ -1599,7 +1600,7 @@ class moduleWeatherAPIRoute
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getNestedRecordValue(array $record, string $path): mixed
|
||||
private static function getNestedRecordValue(array $record, string $path): mixed
|
||||
{
|
||||
$segments = explode('.', $path);
|
||||
$current = $record;
|
||||
@@ -1627,7 +1628,7 @@ class moduleWeatherAPIRoute
|
||||
return $current;
|
||||
}
|
||||
|
||||
private function firstShiftDateTimeFromPaths(array $record, array $paths): ?DateTime
|
||||
private static function firstShiftDateTimeFromPaths(array $record, array $paths): ?DateTime
|
||||
{
|
||||
foreach ($paths as $path) {
|
||||
$value = self::getNestedRecordValue($record, $path);
|
||||
@@ -1640,7 +1641,7 @@ class moduleWeatherAPIRoute
|
||||
return null;
|
||||
}
|
||||
|
||||
private function lastShiftDateTimeFromPaths(array $record, array $paths): ?DateTime
|
||||
private static function lastShiftDateTimeFromPaths(array $record, array $paths): ?DateTime
|
||||
{
|
||||
$latest = null;
|
||||
|
||||
@@ -1659,7 +1660,7 @@ class moduleWeatherAPIRoute
|
||||
return $latest;
|
||||
}
|
||||
|
||||
private function hasShiftApproval(array $record): bool
|
||||
private static function hasShiftApproval(array $record): bool
|
||||
{
|
||||
if (!array_key_exists('approval', $record)) {
|
||||
return false;
|
||||
@@ -1680,7 +1681,7 @@ class moduleWeatherAPIRoute
|
||||
return true;
|
||||
}
|
||||
|
||||
private function resolveEffectiveShiftEnd(array $record, DateTime $shift_start, DateTime $shift_end): DateTime
|
||||
private static function resolveEffectiveShiftEnd(array $record, DateTime $shift_start, DateTime $shift_end): DateTime
|
||||
{
|
||||
if (self::hasShiftApproval($record)) {
|
||||
return $shift_end;
|
||||
@@ -1711,7 +1712,7 @@ class moduleWeatherAPIRoute
|
||||
return $update_time;
|
||||
}
|
||||
|
||||
private function calculateWorkfeedEmployeeHoursForHour(
|
||||
private static function calculateWorkfeedEmployeeHoursForHour(
|
||||
array $shifts,
|
||||
string|array $workfeed_department_ids,
|
||||
DateTime $slot_start,
|
||||
@@ -1775,8 +1776,8 @@ class moduleWeatherAPIRoute
|
||||
if (defined('redis')) {
|
||||
try {
|
||||
$employeeNameCache = new redis();
|
||||
} catch (Exception) {
|
||||
$employeeNameCache = null;
|
||||
} catch (Exception $e) {
|
||||
// Redis is unavailable, proceed without caching.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1822,7 +1823,8 @@ class moduleWeatherAPIRoute
|
||||
$employees = $this->resolveMissingWorkfeedEmployeeNames(
|
||||
$employees,
|
||||
$employeeNameCache,
|
||||
$resolved_employee_names_by_id
|
||||
$resolved_employee_names_by_id,
|
||||
$workfeed
|
||||
);
|
||||
if ($employees === []) {
|
||||
continue;
|
||||
@@ -1851,7 +1853,7 @@ class moduleWeatherAPIRoute
|
||||
}
|
||||
}
|
||||
|
||||
private function calculateWorkfeedEmployeeHoursForHourByEmployee(
|
||||
private static function calculateWorkfeedEmployeeHoursForHourByEmployee(
|
||||
array $shifts,
|
||||
string|array $workfeed_department_ids,
|
||||
DateTime $slot_start,
|
||||
@@ -1902,7 +1904,11 @@ class moduleWeatherAPIRoute
|
||||
|
||||
$employee_identity = self::extractWorkfeedEmployeeIdentity($shift);
|
||||
$employee_id = $employee_identity['id'];
|
||||
$employee_name = self::normalizeShiftTextValue($employee_identity['name'] ?? null) ?? 'Unknown employee';
|
||||
$employee_name = self::normalizeShiftTextValue($employee_identity['name'] ?? null);
|
||||
if ($employee_id === null && $employee_name === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$employee_key = $employee_id ?? ('name:' . strtolower($employee_name));
|
||||
if (!isset($hours_by_employee_key[$employee_key])) {
|
||||
$hours_by_employee_key[$employee_key] = [
|
||||
@@ -1929,8 +1935,14 @@ class moduleWeatherAPIRoute
|
||||
}));
|
||||
}
|
||||
|
||||
private function resolveMissingWorkfeedEmployeeNames(array $employees, ?redis $employee_name_cache, array &$resolved_names_by_employee_id): array
|
||||
private function resolveMissingWorkfeedEmployeeNames(
|
||||
array $employees,
|
||||
?redis $employee_name_cache,
|
||||
array &$resolved_names_by_employee_id,
|
||||
?workfeed $workfeed = null
|
||||
): array
|
||||
{
|
||||
$ids_to_fetch = [];
|
||||
foreach ($employees as &$employee) {
|
||||
$employee_id = self::normalizeShiftTextValue($employee['employee_id'] ?? null);
|
||||
if ($employee_id === null) {
|
||||
@@ -1949,6 +1961,35 @@ class moduleWeatherAPIRoute
|
||||
);
|
||||
}
|
||||
|
||||
if ($resolved_names_by_employee_id[$employee_id] === null) {
|
||||
$ids_to_fetch[$employee_id] = true;
|
||||
}
|
||||
}
|
||||
unset($employee);
|
||||
|
||||
if ($ids_to_fetch !== [] && $workfeed !== null) {
|
||||
$api_names_by_employee_id = $this->fetchWorkfeedEmployeeDisplayNames(
|
||||
$workfeed,
|
||||
array_keys($ids_to_fetch),
|
||||
$employee_name_cache
|
||||
);
|
||||
|
||||
foreach (array_keys($ids_to_fetch) as $employee_id) {
|
||||
$resolved_names_by_employee_id[$employee_id] = $api_names_by_employee_id[$employee_id] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($employees as &$employee) {
|
||||
$employee_id = self::normalizeShiftTextValue($employee['employee_id'] ?? null);
|
||||
if ($employee_id === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$employee_name = self::normalizeShiftTextValue($employee['employee_name'] ?? null);
|
||||
if (!self::isMissingEmployeeDisplayName($employee_name, $employee_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$resolved_name = $resolved_names_by_employee_id[$employee_id] ?? null;
|
||||
if ($resolved_name !== null) {
|
||||
$employee['employee_name'] = $resolved_name;
|
||||
@@ -1960,7 +2001,172 @@ class moduleWeatherAPIRoute
|
||||
return strcasecmp((string)($left['employee_name'] ?? ''), (string)($right['employee_name'] ?? ''));
|
||||
});
|
||||
|
||||
return $employees;
|
||||
return array_values(array_filter($employees, static function (array $employee): bool {
|
||||
$employee_id = self::normalizeShiftTextValue($employee['employee_id'] ?? null);
|
||||
$employee_name = self::normalizeShiftTextValue($employee['employee_name'] ?? null);
|
||||
|
||||
return !self::isMissingEmployeeDisplayName($employee_name, $employee_id);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int,string> $employee_ids
|
||||
* @return array<string,string>
|
||||
*/
|
||||
private function fetchWorkfeedEmployeeDisplayNames(workfeed $workfeed, array $employee_ids, ?redis $employee_name_cache): array
|
||||
{
|
||||
$employee_id_lookup = [];
|
||||
foreach ($employee_ids as $employee_id) {
|
||||
$normalized = self::normalizeShiftTextValue($employee_id);
|
||||
if ($normalized !== null) {
|
||||
$employee_id_lookup[$normalized] = true;
|
||||
}
|
||||
}
|
||||
if ($employee_id_lookup === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$names_by_employee_id = [];
|
||||
try {
|
||||
$employees = self::normalizeWorkfeedCollection($workfeed->listEmployees());
|
||||
} catch (Exception) {
|
||||
$employees = [];
|
||||
}
|
||||
|
||||
foreach ($employees as $employee) {
|
||||
$this->appendWorkfeedEmployeeDisplayNames($employee, $employee_id_lookup, $names_by_employee_id, $employee_name_cache);
|
||||
}
|
||||
|
||||
foreach (array_keys($employee_id_lookup) as $employee_id) {
|
||||
if (isset($names_by_employee_id[$employee_id])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$employee = $workfeed->getEmployee($employee_id);
|
||||
} catch (Exception) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->appendWorkfeedEmployeeDisplayNames($employee, $employee_id_lookup, $names_by_employee_id, $employee_name_cache);
|
||||
}
|
||||
|
||||
return $names_by_employee_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,bool> $employee_id_lookup
|
||||
* @param array<string,string> $names_by_employee_id
|
||||
*/
|
||||
private function appendWorkfeedEmployeeDisplayNames(
|
||||
mixed $employee,
|
||||
array $employee_id_lookup,
|
||||
array &$names_by_employee_id,
|
||||
?redis $employee_name_cache
|
||||
): void {
|
||||
foreach (self::extractWorkfeedEmployeeIds($employee) as $employee_id) {
|
||||
if (!isset($employee_id_lookup[$employee_id])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$employee_name = self::extractWorkfeedEmployeeDisplayName($employee, $employee_id);
|
||||
if ($employee_name === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$names_by_employee_id[$employee_id] = $employee_name;
|
||||
$this->cacheWorkfeedEmployeeDisplayName($employee_name_cache, $employee_id, $employee_name);
|
||||
}
|
||||
}
|
||||
|
||||
private static function extractWorkfeedEmployeeDisplayName(mixed $employee, ?string $employee_id = null): ?string
|
||||
{
|
||||
return workfeed_employee_name_formatter::fromRecord($employee, [
|
||||
'firstname',
|
||||
'firstName',
|
||||
'first_name',
|
||||
'employee.firstname',
|
||||
'employee.firstName',
|
||||
'employee.first_name',
|
||||
'user.firstname',
|
||||
'user.firstName',
|
||||
'user.first_name',
|
||||
], [
|
||||
'lastname',
|
||||
'lastName',
|
||||
'last_name',
|
||||
'employee.lastname',
|
||||
'employee.lastName',
|
||||
'employee.last_name',
|
||||
'user.lastname',
|
||||
'user.lastName',
|
||||
'user.last_name',
|
||||
], [
|
||||
'employeeName',
|
||||
'employee.name',
|
||||
'employee.fullName',
|
||||
'employee.full_name',
|
||||
'employee.displayName',
|
||||
'employee.display_name',
|
||||
'name',
|
||||
'fullName',
|
||||
'full_name',
|
||||
'displayName',
|
||||
'display_name',
|
||||
'user.name',
|
||||
'user.fullName',
|
||||
'user.full_name',
|
||||
'user.displayName',
|
||||
'user.display_name',
|
||||
], $employee_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int,string>
|
||||
*/
|
||||
private static function extractWorkfeedEmployeeIds(mixed $employee): array
|
||||
{
|
||||
$record = self::normalizeWorkfeedRecord($employee);
|
||||
if ($record === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$employee_ids = [];
|
||||
foreach ([
|
||||
'id',
|
||||
'employeeID',
|
||||
'employeeId',
|
||||
'employee_id',
|
||||
'uuid',
|
||||
'employee.id',
|
||||
'employee.employeeID',
|
||||
'employee.employeeId',
|
||||
'employee.employee_id',
|
||||
'employee.uuid',
|
||||
'employeeUUID',
|
||||
'employee_uuid',
|
||||
'user.id',
|
||||
'userId',
|
||||
] as $path) {
|
||||
$employee_id = self::normalizeShiftTextValue(self::getNestedRecordValue($record, $path));
|
||||
if ($employee_id !== null) {
|
||||
$employee_ids[$employee_id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return array_keys($employee_ids);
|
||||
}
|
||||
|
||||
private function cacheWorkfeedEmployeeDisplayName(?redis $employee_name_cache, string $employee_id, string $employee_name): void
|
||||
{
|
||||
if ($employee_name_cache === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$employee_name_cache->cache_workfeed_employee_name($employee_id, $employee_name);
|
||||
} catch (Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
private function fetchCachedWorkfeedEmployeeDisplayName(?redis $employee_name_cache, string $employee_id): ?string
|
||||
@@ -1978,20 +2184,12 @@ class moduleWeatherAPIRoute
|
||||
return self::isMissingEmployeeDisplayName($employee_name, $employee_id) ? null : $employee_name;
|
||||
}
|
||||
|
||||
private function isMissingEmployeeDisplayName(?string $employee_name, ?string $employee_id = null): bool
|
||||
private static function isMissingEmployeeDisplayName(?string $employee_name, ?string $employee_id = null): bool
|
||||
{
|
||||
if ($employee_name === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($employee_id !== null && strcasecmp($employee_name, 'Employee ' . $employee_id) === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return strcasecmp($employee_name, 'Unknown employee') === 0;
|
||||
return workfeed_employee_name_formatter::isMissingDisplayName($employee_name, $employee_id);
|
||||
}
|
||||
|
||||
private function extractWorkfeedEmployeeIdentity(mixed $shift): array
|
||||
private static function extractWorkfeedEmployeeIdentity(mixed $shift): array
|
||||
{
|
||||
$record = self::normalizeWorkfeedRecord($shift);
|
||||
|
||||
@@ -2017,8 +2215,27 @@ class moduleWeatherAPIRoute
|
||||
}
|
||||
}
|
||||
|
||||
$employee_name = null;
|
||||
foreach ([
|
||||
$employee_name = workfeed_employee_name_formatter::fromRecord($record, [
|
||||
'employee.firstname',
|
||||
'employee.firstName',
|
||||
'employee.first_name',
|
||||
'firstname',
|
||||
'firstName',
|
||||
'first_name',
|
||||
'user.firstname',
|
||||
'user.firstName',
|
||||
'user.first_name',
|
||||
], [
|
||||
'employee.lastname',
|
||||
'employee.lastName',
|
||||
'employee.last_name',
|
||||
'lastname',
|
||||
'lastName',
|
||||
'last_name',
|
||||
'user.lastname',
|
||||
'user.lastName',
|
||||
'user.last_name',
|
||||
], [
|
||||
'employeeName',
|
||||
'employee.name',
|
||||
'employee.fullName',
|
||||
@@ -2035,37 +2252,7 @@ class moduleWeatherAPIRoute
|
||||
'user.full_name',
|
||||
'user.displayName',
|
||||
'user.display_name',
|
||||
] as $path) {
|
||||
$value = self::normalizeShiftTextValue(self::getNestedRecordValue($record, $path));
|
||||
if ($value !== null) {
|
||||
$employee_name = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($employee_name === null) {
|
||||
$first_name = self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'employee.firstname'))
|
||||
?? self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'employee.firstName'))
|
||||
?? self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'employee.first_name'))
|
||||
?? self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'firstname'))
|
||||
?? self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'firstName'))
|
||||
?? self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'first_name'));
|
||||
$last_name = self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'employee.lastname'))
|
||||
?? self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'employee.lastName'))
|
||||
?? self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'employee.last_name'))
|
||||
?? self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'lastname'))
|
||||
?? self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'lastName'))
|
||||
?? self::normalizeShiftTextValue(self::getNestedRecordValue($record, 'last_name'));
|
||||
|
||||
$combined_name = trim((string)($first_name ?? '') . ' ' . (string)($last_name ?? ''));
|
||||
if ($combined_name !== '') {
|
||||
$employee_name = $combined_name;
|
||||
}
|
||||
}
|
||||
|
||||
if ($employee_name === null) {
|
||||
$employee_name = 'Unknown employee';
|
||||
}
|
||||
], $employee_id);
|
||||
|
||||
return [
|
||||
'id' => $employee_id,
|
||||
@@ -2073,7 +2260,7 @@ class moduleWeatherAPIRoute
|
||||
];
|
||||
}
|
||||
|
||||
private function normalizeShiftTextValue(mixed $value): ?string
|
||||
private static function normalizeShiftTextValue(mixed $value): ?string
|
||||
{
|
||||
if (!is_scalar($value)) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user