436 lines
16 KiB
PHP
436 lines
16 KiB
PHP
<?php
|
|
|
|
namespace App\Services\User;
|
|
|
|
use App\BusinessLocation;
|
|
use App\Category;
|
|
use App\EmploymentAssignment;
|
|
use App\Services\Holding\HoldingHrmSyncService;
|
|
use App\User;
|
|
use App\Utils\ModuleUtil;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Spatie\Activitylog\Models\Activity;
|
|
|
|
class UserProfileDataService
|
|
{
|
|
public function __construct(
|
|
private ModuleUtil $moduleUtil,
|
|
private HoldingHrmSyncService $holdingHrmSyncService
|
|
) {
|
|
}
|
|
|
|
public function build(User $user, array $options = []): array
|
|
{
|
|
$viewer = $options['viewer'] ?? auth()->user();
|
|
$businessId = (int) $user->business_id;
|
|
$isSelf = $viewer && (int) $viewer->id === (int) $user->id;
|
|
$isAdmin = $viewer ? $this->moduleUtil->is_admin($viewer, $businessId) : false;
|
|
$essentialsEnabled = $this->essentialsEnabled($businessId);
|
|
|
|
$user->loadMissing(['media', 'contactAccess', 'assignments.entity', 'assignments.orgUnit', 'roles']);
|
|
|
|
$department = $user->essentials_department_id
|
|
? Category::find($user->essentials_department_id)
|
|
: null;
|
|
$designation = $user->essentials_designation_id
|
|
? Category::find($user->essentials_designation_id)
|
|
: null;
|
|
$workLocation = $user->location_id
|
|
? BusinessLocation::find($user->location_id)
|
|
: null;
|
|
|
|
$primaryAssignment = EmploymentAssignment::where('business_id', $businessId)
|
|
->where('user_id', $user->id)
|
|
->where('is_primary', true)
|
|
->with(['entity', 'orgUnit'])
|
|
->first();
|
|
|
|
$holdingContext = $this->holdingHrmSyncService->getUserFormContext($businessId, $user);
|
|
|
|
$monthStart = Carbon::now()->startOfMonth()->format('Y-m-d');
|
|
$monthEnd = Carbon::now()->endOfMonth()->format('Y-m-d');
|
|
$yearStart = Carbon::now()->startOfYear()->format('Y-m-d');
|
|
$yearEnd = Carbon::now()->endOfYear()->format('Y-m-d');
|
|
|
|
$stats = [
|
|
'logged_hours' => 0,
|
|
'open_tasks' => 0,
|
|
'approved_leaves' => 0,
|
|
'payroll_count' => 0,
|
|
'support_tickets' => 0,
|
|
'open_support_tickets' => 0,
|
|
];
|
|
$sidebar = [
|
|
'leaves_taken' => 0,
|
|
'late_attendance' => 0,
|
|
'open_tasks' => [],
|
|
'recent_tickets' => [],
|
|
];
|
|
$attendanceRows = collect();
|
|
$leaveRows = collect();
|
|
$taskRows = collect();
|
|
$payrollRows = collect();
|
|
$ticketRows = collect();
|
|
|
|
if ($essentialsEnabled && $this->canViewEssentialsData($viewer, $user, $isSelf, $isAdmin)) {
|
|
$essentialsUtil = app(\Modules\Essentials\Utils\EssentialsUtil::class);
|
|
|
|
$stats['logged_hours'] = (float) str_replace(',', '', $essentialsUtil->getTotalWorkDuration(
|
|
'hour',
|
|
$user->id,
|
|
$businessId,
|
|
$monthStart,
|
|
$monthEnd
|
|
));
|
|
|
|
$stats['open_tasks'] = $this->countOpenTasks($user->id);
|
|
$stats['approved_leaves'] = $this->countApprovedLeaves($businessId, $user->id, $yearStart, $yearEnd);
|
|
$stats['payroll_count'] = $essentialsUtil->getPayrollQuery($businessId)
|
|
->where('transactions.expense_for', $user->id)
|
|
->count();
|
|
|
|
$sidebar['leaves_taken'] = $stats['approved_leaves'];
|
|
$sidebar['late_attendance'] = $this->countLateAttendance($businessId, $user->id, $yearStart, $yearEnd);
|
|
$sidebar['open_tasks'] = $this->getOpenTasks($user->id, 5);
|
|
|
|
$attendanceRows = $this->getRecentAttendance($businessId, $user->id, 10);
|
|
$leaveRows = $this->getRecentLeaves($businessId, $user->id, 10);
|
|
$taskRows = $this->getOpenTasks($user->id, 20);
|
|
$payrollRows = $essentialsUtil->getPayrollQuery($businessId)
|
|
->where('transactions.expense_for', $user->id)
|
|
->orderBy('transaction_date', 'desc')
|
|
->limit(10)
|
|
->get();
|
|
}
|
|
|
|
$ticketsEnabled = $this->ticketsEnabled($businessId);
|
|
if ($ticketsEnabled && $this->canViewTickets($viewer, $user, $isSelf, $isAdmin)) {
|
|
$ticketStats = $this->getTicketStats($businessId, $user->id);
|
|
$stats['support_tickets'] = $ticketStats['total'];
|
|
$stats['open_support_tickets'] = $ticketStats['open'];
|
|
$sidebar['recent_tickets'] = $this->getRecentTickets($businessId, $user->id, 5);
|
|
$ticketRows = $this->getRecentTickets($businessId, $user->id, 20);
|
|
}
|
|
|
|
$lastActivity = Activity::forSubject($user)->latest()->first();
|
|
$lastActivityAt = $lastActivity?->created_at ?? $user->updated_at;
|
|
|
|
$tabs = $this->resolveTabs($essentialsEnabled, $viewer, $user, $isSelf, $isAdmin, $options);
|
|
|
|
$mt_skills = collect();
|
|
$mt_scores = collect();
|
|
$mt_total_score_points = 0;
|
|
if ($this->managementToolsEnabled($businessId)) {
|
|
$mtUtil = app(\Modules\ManagementTools\Utils\ManagementToolsUtil::class);
|
|
$mt_skills = $mtUtil->getUserSkillsList($businessId, $user->id);
|
|
$mt_scores = $mtUtil->getUserRecentScores($businessId, $user->id, 6);
|
|
$mt_total_score_points = $mtUtil->getUserTotalScorePoints($businessId, $user->id);
|
|
}
|
|
|
|
return [
|
|
'user' => $user,
|
|
'employee_id' => 'EMP-'.str_pad((string) $user->id, 3, '0', STR_PAD_LEFT),
|
|
'avatar_url' => $this->avatarUrl($user),
|
|
'department' => $department,
|
|
'designation' => $designation,
|
|
'work_location' => $workLocation,
|
|
'primary_assignment' => $primaryAssignment ?: $holdingContext['primaryAssignment'],
|
|
'holding_url' => $holdingContext['holdingUrl'],
|
|
'last_activity_at' => $lastActivityAt,
|
|
'stats' => $stats,
|
|
'sidebar' => $sidebar,
|
|
'attendance_rows' => $attendanceRows,
|
|
'leave_rows' => $leaveRows,
|
|
'task_rows' => $taskRows,
|
|
'payroll_rows' => $payrollRows,
|
|
'ticket_rows' => $ticketRows,
|
|
'tickets_enabled' => $ticketsEnabled ?? false,
|
|
'tickets_url' => ($ticketsEnabled ?? false)
|
|
? action([\Modules\ManagementTools\Http\Controllers\TicketController::class, 'index'])
|
|
: null,
|
|
'tabs' => $tabs,
|
|
'is_self' => $isSelf,
|
|
'can_edit' => $viewer && ($isSelf || $viewer->can('user.update')),
|
|
'essentials_enabled' => $essentialsEnabled,
|
|
'attendance_url' => $essentialsEnabled
|
|
? action([\Modules\Essentials\Http\Controllers\AttendanceController::class, 'index']).'?employee_id='.$user->id
|
|
: null,
|
|
'leaves_url' => $essentialsEnabled
|
|
? action([\Modules\Essentials\Http\Controllers\EssentialsLeaveController::class, 'index']).'?user_id='.$user->id
|
|
: null,
|
|
'mt_skills' => $mt_skills,
|
|
'mt_scores' => $mt_scores,
|
|
'mt_total_score_points' => $mt_total_score_points,
|
|
'mt_my_scores_url' => $this->managementToolsEnabled($businessId)
|
|
? action([\Modules\ManagementTools\Http\Controllers\ScoreController::class, 'myScores'])
|
|
: null,
|
|
'management_tools_enabled' => $this->managementToolsEnabled($businessId),
|
|
];
|
|
}
|
|
|
|
private function essentialsEnabled(int $businessId): bool
|
|
{
|
|
return $this->moduleUtil->isModuleInstalled('Essentials')
|
|
&& $this->moduleUtil->hasThePermissionInSubscription($businessId, 'essentials_module');
|
|
}
|
|
|
|
private function canViewEssentialsData($viewer, User $user, bool $isSelf, bool $isAdmin): bool
|
|
{
|
|
if (! $viewer) {
|
|
return false;
|
|
}
|
|
|
|
if ($isSelf) {
|
|
return true;
|
|
}
|
|
|
|
if ($isAdmin || $viewer->can('essentials.crud_all_attendance')) {
|
|
return true;
|
|
}
|
|
|
|
return $viewer->can('user.view');
|
|
}
|
|
|
|
private function resolveTabs(
|
|
bool $essentialsEnabled,
|
|
$viewer,
|
|
User $user,
|
|
bool $isSelf,
|
|
bool $isAdmin,
|
|
array $options
|
|
): array {
|
|
$tabs = [
|
|
'profile' => [
|
|
'id' => 'profile_tab',
|
|
'label' => __('lang_v1.profile_tab_profile'),
|
|
'icon' => 'fa-user',
|
|
'enabled' => true,
|
|
],
|
|
];
|
|
|
|
if ($essentialsEnabled && $this->canViewEssentialsData($viewer, $user, $isSelf, $isAdmin)) {
|
|
$tabs['attendance'] = [
|
|
'id' => 'attendance_tab',
|
|
'label' => __('lang_v1.profile_tab_attendance'),
|
|
'icon' => 'fa-clock',
|
|
'enabled' => true,
|
|
];
|
|
$tabs['leaves'] = [
|
|
'id' => 'leaves_tab',
|
|
'label' => __('lang_v1.profile_tab_leaves'),
|
|
'icon' => 'fa-plane',
|
|
'enabled' => true,
|
|
];
|
|
$tabs['tasks'] = [
|
|
'id' => 'tasks_tab',
|
|
'label' => __('lang_v1.profile_tab_tasks'),
|
|
'icon' => 'fa-tasks',
|
|
'enabled' => true,
|
|
];
|
|
if ($isSelf || $isAdmin || ($viewer && $viewer->can('essentials.view_all_payroll'))) {
|
|
$tabs['payroll'] = [
|
|
'id' => 'payroll_tab',
|
|
'label' => __('lang_v1.profile_tab_payroll'),
|
|
'icon' => 'fa-money-bill',
|
|
'enabled' => true,
|
|
];
|
|
}
|
|
}
|
|
|
|
$tabs['documents'] = [
|
|
'id' => 'documents_tab',
|
|
'label' => __('lang_v1.profile_tab_documents'),
|
|
'icon' => 'fa-paperclip',
|
|
'enabled' => true,
|
|
];
|
|
|
|
if ($this->ticketsEnabled((int) $user->business_id) && $this->canViewTickets($viewer, $user, $isSelf, $isAdmin)) {
|
|
$tabs['tickets'] = [
|
|
'id' => 'tickets_tab',
|
|
'label' => __('lang_v1.profile_tab_tickets'),
|
|
'icon' => 'fa-life-ring',
|
|
'enabled' => true,
|
|
];
|
|
}
|
|
|
|
if (empty($options['hide_activities'])) {
|
|
$tabs['activities'] = [
|
|
'id' => 'activities_tab',
|
|
'label' => __('lang_v1.profile_tab_activities'),
|
|
'icon' => 'fa-history',
|
|
'enabled' => true,
|
|
];
|
|
}
|
|
|
|
if (! empty($options['show_edit_tab'])) {
|
|
$tabs['edit'] = [
|
|
'id' => 'edit_tab',
|
|
'label' => __('lang_v1.profile_tab_edit'),
|
|
'icon' => 'fa-edit',
|
|
'enabled' => true,
|
|
];
|
|
$tabs['password'] = [
|
|
'id' => 'password_tab',
|
|
'label' => __('user.change_password'),
|
|
'icon' => 'fa-lock',
|
|
'enabled' => true,
|
|
];
|
|
}
|
|
|
|
return $tabs;
|
|
}
|
|
|
|
private function avatarUrl(User $user): string
|
|
{
|
|
if (! empty($user->media->display_url)) {
|
|
return $user->media->display_url;
|
|
}
|
|
|
|
$palette = ['0074ba', '16cdc7', '36c76c', '7c3aed', 'f97316', 'ff6692', '46caeb', 'e6a800'];
|
|
$background = $palette[$user->id % count($palette)];
|
|
|
|
return 'https://ui-avatars.com/api/?name='.urlencode($user->user_full_name).'&background='.$background.'&color=fff&size=200&bold=true';
|
|
}
|
|
|
|
private function countOpenTasks(int $userId): int
|
|
{
|
|
if (! class_exists(\Modules\Essentials\Entities\ToDo::class)) {
|
|
return 0;
|
|
}
|
|
|
|
return \Modules\Essentials\Entities\ToDo::whereHas('users', function ($q) use ($userId) {
|
|
$q->where('user_id', $userId);
|
|
})->where('status', '!=', 'completed')->count();
|
|
}
|
|
|
|
private function getOpenTasks(int $userId, int $limit)
|
|
{
|
|
if (! class_exists(\Modules\Essentials\Entities\ToDo::class)) {
|
|
return collect();
|
|
}
|
|
|
|
return \Modules\Essentials\Entities\ToDo::whereHas('users', function ($q) use ($userId) {
|
|
$q->where('user_id', $userId);
|
|
})
|
|
->where('status', '!=', 'completed')
|
|
->orderBy('created_at', 'desc')
|
|
->limit($limit)
|
|
->get();
|
|
}
|
|
|
|
private function countApprovedLeaves(int $businessId, int $userId, string $start, string $end): int
|
|
{
|
|
if (! class_exists(\Modules\Essentials\Entities\EssentialsLeave::class)) {
|
|
return 0;
|
|
}
|
|
|
|
return \Modules\Essentials\Entities\EssentialsLeave::where('business_id', $businessId)
|
|
->where('user_id', $userId)
|
|
->where('status', 'approved')
|
|
->whereDate('start_date', '>=', $start)
|
|
->whereDate('start_date', '<=', $end)
|
|
->count();
|
|
}
|
|
|
|
private function getRecentLeaves(int $businessId, int $userId, int $limit)
|
|
{
|
|
if (! class_exists(\Modules\Essentials\Entities\EssentialsLeave::class)) {
|
|
return collect();
|
|
}
|
|
|
|
return \Modules\Essentials\Entities\EssentialsLeave::where('business_id', $businessId)
|
|
->where('user_id', $userId)
|
|
->with('leave_type')
|
|
->orderBy('start_date', 'desc')
|
|
->limit($limit)
|
|
->get();
|
|
}
|
|
|
|
private function getRecentAttendance(int $businessId, int $userId, int $limit)
|
|
{
|
|
if (! class_exists(\Modules\Essentials\Entities\EssentialsAttendance::class)) {
|
|
return collect();
|
|
}
|
|
|
|
return \Modules\Essentials\Entities\EssentialsAttendance::where('business_id', $businessId)
|
|
->where('user_id', $userId)
|
|
->orderBy('clock_in_time', 'desc')
|
|
->limit($limit)
|
|
->get();
|
|
}
|
|
|
|
private function countLateAttendance(int $businessId, int $userId, string $start, string $end): int
|
|
{
|
|
if (! class_exists(\Modules\Essentials\Entities\EssentialsAttendance::class)) {
|
|
return 0;
|
|
}
|
|
|
|
try {
|
|
return \Modules\Essentials\Entities\EssentialsAttendance::query()
|
|
->from('essentials_attendances as ea')
|
|
->join('essentials_shifts as es', 'es.id', '=', 'ea.essentials_shift_id')
|
|
->where('ea.business_id', $businessId)
|
|
->where('ea.user_id', $userId)
|
|
->whereNotNull('ea.clock_in_time')
|
|
->whereNotNull('es.start_time')
|
|
->whereDate('ea.clock_in_time', '>=', $start)
|
|
->whereDate('ea.clock_in_time', '<=', $end)
|
|
->whereRaw('TIME(ea.clock_in_time) > ADDTIME(es.start_time, "00:15:00")')
|
|
->count();
|
|
} catch (\Throwable $e) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private function ticketsEnabled(int $businessId): bool
|
|
{
|
|
return $this->managementToolsEnabled($businessId)
|
|
&& class_exists(\Modules\ManagementTools\Entities\MtUserTicket::class);
|
|
}
|
|
|
|
private function managementToolsEnabled(int $businessId): bool
|
|
{
|
|
return $this->moduleUtil->isModuleInstalled('ManagementTools')
|
|
&& $this->moduleUtil->hasThePermissionInSubscription($businessId, 'managementtools_module');
|
|
}
|
|
|
|
private function canViewTickets($viewer, User $user, bool $isSelf, bool $isAdmin): bool
|
|
{
|
|
if (! $viewer) {
|
|
return false;
|
|
}
|
|
|
|
if ($isSelf) {
|
|
return $viewer->can('managementtools.ticket_own') || $viewer->can('managementtools.ticket_manage');
|
|
}
|
|
|
|
if ($isAdmin || $viewer->can('managementtools.ticket_manage')) {
|
|
return true;
|
|
}
|
|
|
|
return $viewer->can('user.view');
|
|
}
|
|
|
|
private function getTicketStats(int $businessId, int $userId): array
|
|
{
|
|
$base = \Modules\ManagementTools\Entities\MtUserTicket::forBusiness($businessId)
|
|
->where('user_id', $userId);
|
|
|
|
return [
|
|
'total' => (clone $base)->count(),
|
|
'open' => (clone $base)->open()->count(),
|
|
];
|
|
}
|
|
|
|
private function getRecentTickets(int $businessId, int $userId, int $limit)
|
|
{
|
|
return \Modules\ManagementTools\Entities\MtUserTicket::forBusiness($businessId)
|
|
->where('user_id', $userId)
|
|
->with('assignee')
|
|
->orderByDesc('updated_at')
|
|
->limit($limit)
|
|
->get();
|
|
}
|
|
}
|