ultimatepos/app/Services/Holding/HoldingHrmSyncService.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,
]);
}
}