- Implement tests to ensure job skips execution on weekends, when penalties are zero, or when no payroll period exists. - Validate late penalty creation for late check-ins and ensure no penalties for on-time or early check-ins. - Test absent penalties for employees without attendance records. - Ensure no duplicate penalties are created and that payroll recalculations are accurate after penalties are applied. - Handle multiple employees and edge cases, including employees without associated users. - Verify that the job can be dispatched to the queue and has the correct retry configuration.
635 lines
20 KiB
PHP
635 lines
20 KiB
PHP
<?php
|
|
|
|
use App\Enums\PayrollAdjustmentType;
|
|
use App\Enums\PayrollStatus;
|
|
use App\Jobs\CheckAttendancePenaltiesJob;
|
|
use App\Models\Attendance;
|
|
use App\Models\Employee;
|
|
use App\Models\Payroll;
|
|
use App\Models\PayrollAdjustment;
|
|
use App\Models\PayrollPeriod;
|
|
use App\Models\User;
|
|
use App\Settings\HRSettings;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Queue;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| HELPER
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
function createActiveEmployeeWithPayroll(int $year, int $month, PayrollStatus|string $status = PayrollStatus::UNPAID): array
|
|
{
|
|
$period = PayrollPeriod::firstOrCreate(
|
|
['year' => $year, 'month' => $month],
|
|
['status' => 'open']
|
|
);
|
|
|
|
$user = User::factory()->create(['is_active' => true]);
|
|
$employee = Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => Carbon::createFromDate($year, $month, 1)->subMonth()->toDateString(),
|
|
'resign_date' => null,
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
$payroll = Payroll::factory()->create([
|
|
'payroll_period_id' => $period->id,
|
|
'employee_id' => $employee->id,
|
|
'base_salary' => $employee->base_salary,
|
|
'bonus_amount' => 0,
|
|
'deduction_amount' => 0,
|
|
'total_amount' => $employee->base_salary,
|
|
'status' => $status,
|
|
]);
|
|
|
|
return compact('period', 'user', 'employee', 'payroll');
|
|
}
|
|
|
|
function setHrSettings(int $latePenalty, int $absentPenalty, string $checkInTime = '08:00'): void
|
|
{
|
|
$settings = app(HRSettings::class);
|
|
$settings->scheduled_check_in_time = $checkInTime;
|
|
$settings->scheduled_check_out_time = '17:00';
|
|
$settings->late_penalty_amount = $latePenalty;
|
|
$settings->absent_penalty_amount = $absentPenalty;
|
|
$settings->save();
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| SKIP CONDITIONS
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('job skips when yesterday is sunday', function () {
|
|
$sunday = Carbon::parse('2024-07-07'); // Sunday
|
|
Carbon::setTestNow($sunday->copy()->addDay());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($sunday->year, $sunday->month);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $sunday->toDateString(),
|
|
'check_in_at' => $sunday->copy()->setHour(9),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('job skips when yesterday is saturday', function () {
|
|
$saturday = Carbon::parse('2024-07-06'); // Saturday
|
|
Carbon::setTestNow($saturday->copy()->addDay());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($saturday->year, $saturday->month);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $saturday->toDateString(),
|
|
'check_in_at' => $saturday->copy()->setHour(9),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('job skips when both penalties are zero', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(0, 0);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setHour(9),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('job skips when no payroll period exists', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
|
|
$user = User::factory()->create(['is_active' => true]);
|
|
$employee = Employee::factory()->create([
|
|
'user_id' => $user->id,
|
|
'join_date' => $yesterday->copy()->subMonth()->toDateString(),
|
|
'resign_date' => null,
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('job skips when no system user exists', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
User::query()->delete();
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('job skips inactive employees', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
$data['user']->update(['is_active' => false]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('job skips resigned employees', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
$data['employee']->update(['resign_date' => $yesterday->copy()->subDays(5)->toDateString()]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('job skips when payroll is already paid', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month, PayrollStatus::PAID);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('job skips when payroll is cancelled', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month, PayrollStatus::CANCELLED);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| LATE PENALTY
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('job creates late penalty when employee checks in late', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000, '08:00');
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setHour(8)->setMinute(30),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseHas('payroll_adjustments', [
|
|
'payroll_id' => $data['payroll']->id,
|
|
'type' => PayrollAdjustmentType::DEDUCTION,
|
|
'amount' => 50000,
|
|
]);
|
|
});
|
|
|
|
test('job does not create late penalty when employee checks in on time', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000, '08:00');
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setTime(8, 0, 0),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('job does not create late penalty when employee checks in early', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000, '08:00');
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setTime(7, 30, 0),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('job does not create late penalty when late_penalty_amount is zero', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(0, 100000, '08:00');
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setHour(9),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('late penalty description includes date and minutes', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000, '08:00');
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setHour(8)->setMinute(30),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$adjustment = PayrollAdjustment::where('payroll_id', $data['payroll']->id)->first();
|
|
expect($adjustment->description)->toContain('Denda keterlambatan');
|
|
expect($adjustment->description)->toContain($yesterday->format('d/m/Y'));
|
|
expect($adjustment->description)->toContain('30 menit');
|
|
});
|
|
|
|
test('late penalty links to attendance record', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000, '08:00');
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
$attendance = Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setHour(9),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$adjustment = PayrollAdjustment::where('payroll_id', $data['payroll']->id)->first();
|
|
expect($adjustment->attendance_id)->toBe($attendance->id);
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| ABSENT PENALTY
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('job creates absent penalty when employee has no attendance', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseHas('payroll_adjustments', [
|
|
'payroll_id' => $data['payroll']->id,
|
|
'type' => PayrollAdjustmentType::DEDUCTION,
|
|
'amount' => 100000,
|
|
'attendance_id' => null,
|
|
]);
|
|
});
|
|
|
|
test('job does not create absent penalty when absent_penalty_amount is zero', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 0);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 0);
|
|
});
|
|
|
|
test('absent penalty description includes date', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$adjustment = PayrollAdjustment::where('payroll_id', $data['payroll']->id)->first();
|
|
expect($adjustment->description)->toContain('Denda ketidakhadiran');
|
|
expect($adjustment->description)->toContain($yesterday->format('d/m/Y'));
|
|
});
|
|
|
|
test('absent penalty has null attendance_id', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$adjustment = PayrollAdjustment::where('payroll_id', $data['payroll']->id)->first();
|
|
expect($adjustment->attendance_id)->toBeNull();
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| DEDUPLICATION
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('job does not create duplicate late penalty', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000, '08:00');
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
$attendance = Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setHour(9),
|
|
]);
|
|
|
|
PayrollAdjustment::create([
|
|
'payroll_id' => $data['payroll']->id,
|
|
'created_by_id' => User::first()->id,
|
|
'attendance_id' => $attendance->id,
|
|
'type' => PayrollAdjustmentType::DEDUCTION,
|
|
'amount' => 50000,
|
|
'description' => 'Denda keterlambatan manual',
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 1);
|
|
});
|
|
|
|
test('job does not create duplicate absent penalty', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
PayrollAdjustment::create([
|
|
'payroll_id' => $data['payroll']->id,
|
|
'created_by_id' => User::first()->id,
|
|
'attendance_id' => null,
|
|
'type' => PayrollAdjustmentType::DEDUCTION,
|
|
'amount' => 100000,
|
|
'description' => 'Denda ketidakhadiran '.$yesterday->format('d/m/Y'),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseCount('payroll_adjustments', 1);
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| PAYROLL RECALCULATION
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('job recalculates payroll total_amount after late penalty', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000, '08:00');
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setHour(9),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$data['payroll']->refresh();
|
|
expect($data['payroll']->deduction_amount)->toBe(50000);
|
|
expect($data['payroll']->total_amount)->toBe($data['payroll']->base_salary - 50000);
|
|
});
|
|
|
|
test('job recalculates payroll total_amount after absent penalty', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$data['payroll']->refresh();
|
|
expect($data['payroll']->deduction_amount)->toBe(100000);
|
|
expect($data['payroll']->total_amount)->toBe($data['payroll']->base_salary - 100000);
|
|
});
|
|
|
|
test('job recalculates payroll with existing bonus adjustments', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000, '08:00');
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
PayrollAdjustment::create([
|
|
'payroll_id' => $data['payroll']->id,
|
|
'created_by_id' => User::first()->id,
|
|
'attendance_id' => null,
|
|
'type' => PayrollAdjustmentType::BONUS,
|
|
'amount' => 200000,
|
|
'description' => 'Bonus test',
|
|
]);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setHour(9),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$data['payroll']->refresh();
|
|
expect($data['payroll']->bonus_amount)->toBe(200000);
|
|
expect($data['payroll']->deduction_amount)->toBe(50000);
|
|
expect($data['payroll']->total_amount)->toBe($data['payroll']->base_salary + 200000 - 50000);
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| MULTIPLE EMPLOYEES
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('job processes multiple employees', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000, '08:00');
|
|
|
|
$data1 = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
$data2 = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data1['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setHour(9),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseHas('payroll_adjustments', [
|
|
'payroll_id' => $data1['payroll']->id,
|
|
'type' => PayrollAdjustmentType::DEDUCTION,
|
|
'amount' => 50000,
|
|
]);
|
|
|
|
$this->assertDatabaseHas('payroll_adjustments', [
|
|
'payroll_id' => $data2['payroll']->id,
|
|
'type' => PayrollAdjustmentType::DEDUCTION,
|
|
'amount' => 100000,
|
|
]);
|
|
});
|
|
|
|
test('job handles mix of late and absent employees', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000, '08:00');
|
|
|
|
$lateEmp = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
$absentEmp = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $lateEmp['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setHour(9),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseHas('payroll_adjustments', [
|
|
'payroll_id' => $lateEmp['payroll']->id,
|
|
'amount' => 50000,
|
|
]);
|
|
|
|
$this->assertDatabaseHas('payroll_adjustments', [
|
|
'payroll_id' => $absentEmp['payroll']->id,
|
|
'amount' => 100000,
|
|
]);
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| EDGE CASES
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
test('job handles employee with no user gracefully', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$this->assertDatabaseHas('payroll_adjustments', [
|
|
'payroll_id' => $data['payroll']->id,
|
|
]);
|
|
});
|
|
|
|
test('job uses system user as created_by for adjustments', function () {
|
|
$yesterday = now()->subDay();
|
|
Carbon::setTestNow(now());
|
|
|
|
setHrSettings(50000, 100000);
|
|
$data = createActiveEmployeeWithPayroll($yesterday->year, $yesterday->month);
|
|
|
|
$systemUser = User::first();
|
|
|
|
Attendance::factory()->create([
|
|
'employee_id' => $data['employee']->id,
|
|
'attendance_date' => $yesterday->toDateString(),
|
|
'check_in_at' => $yesterday->copy()->setHour(9),
|
|
]);
|
|
|
|
(new CheckAttendancePenaltiesJob)->handle();
|
|
|
|
$adjustment = PayrollAdjustment::where('payroll_id', $data['payroll']->id)->first();
|
|
expect($adjustment->created_by_id)->toBe($systemUser->id);
|
|
});
|
|
|
|
test('job can be dispatched to queue', function () {
|
|
Queue::fake();
|
|
|
|
CheckAttendancePenaltiesJob::dispatch();
|
|
|
|
Queue::assertPushed(CheckAttendancePenaltiesJob::class);
|
|
});
|
|
|
|
test('job has correct tries property', function () {
|
|
$job = new CheckAttendancePenaltiesJob;
|
|
expect($job->tries)->toBe(3);
|
|
});
|