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' => 'TM', ]); $rows = [[ 'employee_number' => 'EMP-90001', 'full_name' => 'Duplicate Employee', 'national_id' => 'TM', '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('imports valid employee rows without an employee number', function (): void { $rows = [[ 'full_name' => 'Auto Number Employee', 'gender' => 'male', 'birth_date' => '1992-02-20', 'department' => 'Engineering', 'position' => 'Developer', 'shift' => 'Day Shift', 'hire_date' => '2024-04-01', ]]; $result = $this->importService->import(ImportType::Employees, $rows); expect($result->imported)->toBe(1) ->and($result->skipped)->toBe(0) ->and($result->failed)->toBe(0); $employee = Employee::query()->where('full_name', 'Auto Number Employee')->first(); expect($employee)->not->toBeNull() ->and($employee->employee_number)->toBe('EMP-00001'); }); 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('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' => 'TM', ]); $duplicateByNumber = EmployeeRowDto::fromMappedRow([ 'employee_number' => 'EMP-80001', 'full_name' => 'Someone Else', ]); $duplicateByNationalId = EmployeeRowDto::fromMappedRow([ 'employee_number' => 'EMP-80002', 'full_name' => 'Another Person', 'national_id' => 'TM', ]); expect($this->transformer->isDuplicate($duplicateByNumber))->toBeTrue() ->and($this->transformer->isDuplicate($duplicateByNationalId))->toBeTrue(); });