0, 'assignments' => 0, 'designations' => 0]; DB::transaction(function () use ($businessId, &$stats) { $entity = $this->resolveDefaultEntity($businessId); $departments = Category::where('business_id', $businessId) ->where('category_type', 'hrm_department') ->get(); foreach ($departments as $department) { $orgUnit = $this->syncDepartmentCategory($department, $entity); if ($orgUnit && $orgUnit->wasRecentlyCreated) { $stats['departments']++; } } $users = User::where('business_id', $businessId) ->user() ->where(function ($query) { $query->whereNotNull('essentials_department_id') ->orWhereNotNull('essentials_designation_id'); }) ->get(); foreach ($users as $user) { $result = $this->syncUserAssignment($user); if ($result === 'created') { $stats['assignments']++; } elseif ($result === 'updated') { $stats['designations']++; } } }); return $stats; } /** * @return 'created'|'updated'|null */ public function syncUserAssignment(User $user): ?string { if (! config('constants.enable_holding_context_rbac') || $user->user_type !== 'user') { return null; } $businessId = (int) $user->business_id; $departmentId = $user->essentials_department_id; $designationId = $user->essentials_designation_id; if (empty($departmentId) && empty($designationId)) { return null; } return DB::transaction(function () use ($user, $businessId, $departmentId, $designationId) { $entity = $this->resolveDefaultEntity($businessId); if (! empty($departmentId)) { $department = Category::where('business_id', $businessId) ->where('category_type', 'hrm_department') ->find($departmentId); if ($department) { $this->syncDepartmentCategory($department, $entity); } } $orgUnitId = $this->resolveOrgUnitId($businessId, $entity->id, $departmentId); $designation = $this->resolveDesignation($designationId); $meta = [ 'hrm_department_id' => $departmentId, 'hrm_designation_id' => $designationId, ]; $roleId = $user->roles->first()?->id; $assignment = EmploymentAssignment::where('business_id', $businessId) ->where('user_id', $user->id) ->where('entity_id', $entity->id) ->where('is_primary', true) ->first(); $payload = [ 'org_unit_id' => $orgUnitId, 'title' => $designation?->name, 'role_id' => $roleId, 'employment_type' => 'employee', 'is_primary' => true, 'is_active' => true, 'meta' => $meta, ]; if ($assignment) { $payload['meta'] = array_merge($assignment->meta ?? [], $meta); if ($assignment->fill($payload)->isDirty()) { $assignment->save(); return 'updated'; } return null; } EmploymentAssignment::create(array_merge([ 'business_id' => $businessId, 'user_id' => $user->id, 'entity_id' => $entity->id, ], $payload)); return 'created'; }); } public function syncDepartmentCategory(Category $department, ?HoldingEntity $entity = null): ?OrgUnit { if ($department->category_type !== 'hrm_department') { return null; } $entity = $entity ?: $this->resolveDefaultEntity((int) $department->business_id); $orgUnit = OrgUnit::firstOrCreate( [ 'business_id' => $department->business_id, 'entity_id' => $entity->id, 'name' => $department->name, ], [ 'code' => $department->short_code, 'depth' => 0, 'path' => $department->name, 'is_active' => true, 'meta' => ['hrm_department_id' => $department->id], ] ); if (! $orgUnit->wasRecentlyCreated && empty($orgUnit->meta['hrm_department_id'])) { $orgUnit->update([ 'meta' => array_merge($orgUnit->meta ?? [], ['hrm_department_id' => $department->id]), 'code' => $orgUnit->code ?: $department->short_code, ]); } elseif (! $orgUnit->wasRecentlyCreated) { $updates = []; if ($orgUnit->name !== $department->name) { $updates['name'] = $department->name; $updates['path'] = $department->name; } if ($department->short_code && $orgUnit->code !== $department->short_code) { $updates['code'] = $department->short_code; } if (! empty($updates)) { $orgUnit->update($updates); } } return $orgUnit; } public function syncUserHrmFromAssignment(EmploymentAssignment $assignment): void { if (! config('constants.enable_holding_context_rbac')) { return; } $user = $assignment->user; if (empty($user) || $user->user_type !== 'user') { return; } $updates = []; if (! empty($assignment->org_unit_id)) { $orgUnit = OrgUnit::find($assignment->org_unit_id); if (! empty($orgUnit->meta['hrm_department_id'])) { $updates['essentials_department_id'] = $orgUnit->meta['hrm_department_id']; } } if (! empty($assignment->meta['hrm_designation_id'])) { $updates['essentials_designation_id'] = $assignment->meta['hrm_designation_id']; } if (! empty($updates)) { $user->update($updates); } } public function resolveOrgUnitMeta(?int $orgUnitId): array { if (empty($orgUnitId)) { return []; } $orgUnit = OrgUnit::find($orgUnitId); if (empty($orgUnit) || empty($orgUnit->meta['hrm_department_id'])) { return []; } return ['hrm_department_id' => (int) $orgUnit->meta['hrm_department_id']]; } public function getUserFormContext(int $businessId, ?User $user = null): array { $departmentToOrgUnit = OrgUnit::where('business_id', $businessId) ->get(['id', 'name', 'meta']) ->filter(fn ($unit) => ! empty($unit->meta['hrm_department_id'])) ->mapWithKeys(fn ($unit) => [ (int) $unit->meta['hrm_department_id'] => [ 'id' => $unit->id, 'name' => $unit->name, ], ]); $primaryAssignment = null; if ($user) { $primaryAssignment = EmploymentAssignment::where('business_id', $businessId) ->where('user_id', $user->id) ->where('is_primary', true) ->with(['entity', 'orgUnit']) ->first(); } return [ 'departmentToOrgUnit' => $departmentToOrgUnit, 'primaryAssignment' => $primaryAssignment, 'holdingUrl' => route('holding.index'), ]; } public function resolveOrgUnitId(int $businessId, int $entityId, ?int $departmentId): ?int { if (empty($departmentId)) { return null; } $orgUnitId = OrgUnit::where('business_id', $businessId) ->where('entity_id', $entityId) ->where('meta->hrm_department_id', $departmentId) ->value('id'); if (! empty($orgUnitId)) { return (int) $orgUnitId; } $category = Category::find($departmentId); if (empty($category)) { return null; } return OrgUnit::where('business_id', $businessId) ->where('entity_id', $entityId) ->where('name', $category->name) ->value('id'); } public function resolveDesignation(?int $designationId): ?Category { if (empty($designationId)) { return null; } return Category::where('id', $designationId) ->where('category_type', 'hrm_designation') ->first(); } public function resolveTitleFromDesignation(?int $designationId, ?string $fallback = null): ?string { $designation = $this->resolveDesignation($designationId); return $designation?->name ?: $fallback; } public function resolveDefaultEntity(int $businessId): HoldingEntity { $entity = HoldingEntity::where('business_id', $businessId) ->where('entity_type', 'company') ->where('is_internal', true) ->first(); if ($entity) { return $entity; } return $this->entityLocationSyncService->createEntityWithLocation($businessId, [ 'business_id' => $businessId, 'name' => __('lang_v1.holding_default_entity_name', ['id' => $businessId]), 'entity_type' => 'company', 'is_internal' => true, 'is_active' => true, ]); } }