310 lines
9.9 KiB
PHP
310 lines
9.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Holding;
|
|
|
|
use App\Category;
|
|
use App\EmploymentAssignment;
|
|
use App\HoldingEntity;
|
|
use App\OrgUnit;
|
|
use App\User;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class HoldingHrmSyncService
|
|
{
|
|
public function __construct(protected HoldingEntityLocationSyncService $entityLocationSyncService)
|
|
{
|
|
}
|
|
|
|
public function syncForBusiness(int $businessId): array
|
|
{
|
|
$stats = ['departments' => 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,
|
|
]);
|
|
}
|
|
}
|