174 lines
5.0 KiB
PHP
174 lines
5.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services\Import;
|
|
|
|
use App\DTOs\Import\EmployeeRowDto;
|
|
use App\Enums\EmploymentStatus;
|
|
use App\Enums\Gender;
|
|
use App\Models\Department;
|
|
use App\Models\Employee;
|
|
use App\Models\Position;
|
|
use App\Models\Shift;
|
|
use App\Support\Countries;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Str;
|
|
|
|
class EmployeeImportTransformer
|
|
{
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function toAttributes(EmployeeRowDto $dto): array
|
|
{
|
|
return [
|
|
'employee_number' => $dto->employeeNumber !== '' ? $dto->employeeNumber : null,
|
|
'full_name' => $dto->fullName,
|
|
'national_id' => $this->resolveNationality($dto->nationalId),
|
|
'gender' => $this->resolveGender($dto->gender),
|
|
'birth_date' => $this->parseDate($dto->birthDate),
|
|
'phone' => $dto->phone ?? config('hr.default_phone'),
|
|
'address' => $dto->address,
|
|
'department_id' => $this->resolveDepartmentId($dto->department),
|
|
'position_id' => $this->resolvePositionId($dto->position),
|
|
'shift_id' => $this->resolveShiftId($dto->shift),
|
|
'employment_status' => $this->resolveEmploymentStatus($dto->employmentStatus),
|
|
'hire_date' => $this->parseDate($dto->hireDate),
|
|
'notes' => $dto->notes,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<int, string>
|
|
*/
|
|
public function validate(EmployeeRowDto $dto): array
|
|
{
|
|
$errors = [];
|
|
|
|
if ($dto->fullName === '') {
|
|
$errors[] = 'Full name is required.';
|
|
}
|
|
|
|
if ($dto->department && $this->resolveDepartmentId($dto->department) === null) {
|
|
$errors[] = "Department \"{$dto->department}\" was not found.";
|
|
}
|
|
|
|
if ($dto->position && $this->resolvePositionId($dto->position) === null) {
|
|
$errors[] = "Position \"{$dto->position}\" was not found.";
|
|
}
|
|
|
|
if ($dto->shift && $this->resolveShiftId($dto->shift) === null) {
|
|
$errors[] = "Shift \"{$dto->shift}\" was not found.";
|
|
}
|
|
|
|
if ($dto->nationalId && $this->resolveNationality($dto->nationalId) === null) {
|
|
$errors[] = "Nationality \"{$dto->nationalId}\" was not found.";
|
|
}
|
|
|
|
return $errors;
|
|
}
|
|
|
|
public function isDuplicate(EmployeeRowDto $dto): bool
|
|
{
|
|
$hasEmployeeNumber = $dto->employeeNumber !== '';
|
|
$nationality = $this->resolveNationality($dto->nationalId);
|
|
|
|
if (! $hasEmployeeNumber && $nationality === null) {
|
|
return false;
|
|
}
|
|
|
|
return Employee::query()
|
|
->where(function ($query) use ($dto, $hasEmployeeNumber, $nationality): void {
|
|
if ($hasEmployeeNumber) {
|
|
$query->where('employee_number', $dto->employeeNumber);
|
|
}
|
|
|
|
if ($nationality !== null) {
|
|
$hasEmployeeNumber
|
|
? $query->orWhere('national_id', $nationality)
|
|
: $query->where('national_id', $nationality);
|
|
}
|
|
})
|
|
->exists();
|
|
}
|
|
|
|
private function resolveNationality(?string $value): ?string
|
|
{
|
|
return Countries::resolve($value);
|
|
}
|
|
|
|
private function resolveGender(?string $value): ?Gender
|
|
{
|
|
if ($value === null) {
|
|
return null;
|
|
}
|
|
|
|
$normalized = Str::lower(trim($value));
|
|
|
|
return Gender::tryFrom($normalized)
|
|
?? match ($normalized) {
|
|
'm', 'man' => Gender::Male,
|
|
'f', 'woman' => Gender::Female,
|
|
default => null,
|
|
};
|
|
}
|
|
|
|
private function resolveEmploymentStatus(?string $value): EmploymentStatus
|
|
{
|
|
if ($value === null || trim($value) === '') {
|
|
return EmploymentStatus::Active;
|
|
}
|
|
|
|
$normalized = Str::lower(str_replace(' ', '_', trim($value)));
|
|
|
|
return EmploymentStatus::tryFrom($normalized) ?? EmploymentStatus::Active;
|
|
}
|
|
|
|
private function resolveDepartmentId(?string $value): ?int
|
|
{
|
|
if ($value === null || trim($value) === '') {
|
|
return null;
|
|
}
|
|
|
|
return Department::query()
|
|
->where('name', $value)
|
|
->orWhere('code', $value)
|
|
->value('id');
|
|
}
|
|
|
|
private function resolvePositionId(?string $value): ?int
|
|
{
|
|
if ($value === null || trim($value) === '') {
|
|
return null;
|
|
}
|
|
|
|
return Position::query()->where('name', $value)->value('id');
|
|
}
|
|
|
|
private function resolveShiftId(?string $value): ?int
|
|
{
|
|
if ($value === null || trim($value) === '') {
|
|
return null;
|
|
}
|
|
|
|
return Shift::query()
|
|
->where('name', $value)
|
|
->orWhere('code', $value)
|
|
->value('id');
|
|
}
|
|
|
|
private function parseDate(?string $value): ?string
|
|
{
|
|
if ($value === null || trim($value) === '') {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return Carbon::parse($value)->toDateString();
|
|
} catch (\Throwable) {
|
|
return null;
|
|
}
|
|
}
|
|
}
|