123 lines
4.0 KiB
PHP
123 lines
4.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\DTOs\Import\EmployeeRowDto;
|
|
use App\Enums\ImportType;
|
|
use App\Models\Department;
|
|
use App\Models\Employee;
|
|
use App\Models\Position;
|
|
use App\Models\Shift;
|
|
use App\Services\Import\EmployeeImportTransformer;
|
|
use App\Services\Import\ImportService;
|
|
|
|
beforeEach(function (): void {
|
|
$this->department = Department::factory()->create(['name' => 'Engineering', 'code' => 'ENG']);
|
|
$this->position = Position::factory()->create(['name' => 'Developer']);
|
|
$this->shift = Shift::factory()->create(['name' => 'Day Shift', 'code' => 'DAY']);
|
|
$this->importService = app(ImportService::class);
|
|
$this->transformer = app(EmployeeImportTransformer::class);
|
|
});
|
|
|
|
it('skips duplicate employees during import', function (): void {
|
|
Employee::factory()->create([
|
|
'employee_number' => 'EMP-90001',
|
|
'national_id' => '1234567890',
|
|
]);
|
|
|
|
$rows = [[
|
|
'employee_number' => 'EMP-90001',
|
|
'full_name' => 'Duplicate Employee',
|
|
'national_id' => '1234567890',
|
|
'department' => 'Engineering',
|
|
'position' => 'Developer',
|
|
'shift' => 'Day Shift',
|
|
'hire_date' => '2024-01-01',
|
|
]];
|
|
|
|
$result = $this->importService->import(ImportType::Employees, $rows);
|
|
|
|
expect($result->imported)->toBe(0)
|
|
->and($result->skipped)->toBe(1)
|
|
->and($result->failed)->toBe(0)
|
|
->and(Employee::query()->where('employee_number', 'EMP-90001')->count())->toBe(1);
|
|
});
|
|
|
|
it('imports valid employee rows', function (): void {
|
|
$rows = [[
|
|
'employee_number' => 'EMP-90002',
|
|
'full_name' => 'Jane Smith',
|
|
'gender' => 'female',
|
|
'birth_date' => '1990-01-15',
|
|
'department' => 'Engineering',
|
|
'position' => 'Developer',
|
|
'shift' => 'Day Shift',
|
|
'hire_date' => '2024-03-15',
|
|
]];
|
|
|
|
$result = $this->importService->import(ImportType::Employees, $rows);
|
|
|
|
expect($result->imported)->toBe(1)
|
|
->and($result->skipped)->toBe(0)
|
|
->and($result->failed)->toBe(0);
|
|
|
|
$this->assertDatabaseHas('employees', [
|
|
'employee_number' => 'EMP-90002',
|
|
'full_name' => 'Jane Smith',
|
|
'department_id' => $this->department->id,
|
|
]);
|
|
});
|
|
|
|
it('reports validation errors for invalid employee rows', function (): void {
|
|
$rows = [[
|
|
'employee_number' => '',
|
|
'full_name' => '',
|
|
'department' => 'Unknown Department',
|
|
]];
|
|
|
|
$result = $this->importService->import(ImportType::Employees, $rows);
|
|
|
|
expect($result->imported)->toBe(0)
|
|
->and($result->failed)->toBe(1)
|
|
->and($result->errors)->not->toBeEmpty();
|
|
});
|
|
|
|
it('validates required fields and unknown references', function (): void {
|
|
$dto = EmployeeRowDto::fromMappedRow([
|
|
'employee_number' => '',
|
|
'full_name' => '',
|
|
'department' => 'Missing Department',
|
|
'position' => 'Missing Position',
|
|
'shift' => 'Missing Shift',
|
|
]);
|
|
|
|
$errors = $this->transformer->validate($dto);
|
|
|
|
expect($errors)->toContain('Employee number is required.')
|
|
->and($errors)->toContain('Full name is required.')
|
|
->and($errors)->toContain('Department "Missing Department" was not found.')
|
|
->and($errors)->toContain('Position "Missing Position" was not found.')
|
|
->and($errors)->toContain('Shift "Missing Shift" was not found.');
|
|
});
|
|
|
|
it('detects duplicates by employee number or national id', function (): void {
|
|
Employee::factory()->create([
|
|
'employee_number' => 'EMP-80001',
|
|
'national_id' => '9988776655',
|
|
]);
|
|
|
|
$duplicateByNumber = EmployeeRowDto::fromMappedRow([
|
|
'employee_number' => 'EMP-80001',
|
|
'full_name' => 'Someone Else',
|
|
]);
|
|
|
|
$duplicateByNationalId = EmployeeRowDto::fromMappedRow([
|
|
'employee_number' => 'EMP-80002',
|
|
'full_name' => 'Another Person',
|
|
'national_id' => '9988776655',
|
|
]);
|
|
|
|
expect($this->transformer->isDuplicate($duplicateByNumber))->toBeTrue()
|
|
->and($this->transformer->isDuplicate($duplicateByNationalId))->toBeTrue();
|
|
});
|