feat: update payroll generation logic to schedule on the 5th of each month and adjust attendance penalties calculation

This commit is contained in:
Yoga Pangestu 2026-08-14 04:08:13 +07:00
parent 9d4f6c94ea
commit 7fa20fbc3c
6 changed files with 67 additions and 38 deletions

View File

@ -4,6 +4,7 @@
use App\Enums\PayrollPeriodStatus; use App\Enums\PayrollPeriodStatus;
use App\Enums\PayrollStatus; use App\Enums\PayrollStatus;
use App\Enums\Role;
use App\Models\Employee; use App\Models\Employee;
use App\Models\Payroll; use App\Models\Payroll;
use App\Models\PayrollPeriod; use App\Models\PayrollPeriod;
@ -13,7 +14,7 @@ class GeneratePayrollCommand extends Command
{ {
protected $signature = 'payroll:generate'; protected $signature = 'payroll:generate';
protected $description = 'Generate payroll for all active employees for the current month'; protected $description = 'Generate payroll for all active employees (scheduled on 5th of each month)';
public function handle(): int public function handle(): int
{ {
@ -33,6 +34,7 @@ public function handle(): int
} }
$employees = Employee::whereHas('user', fn ($q) => $q->where('is_active', true)) $employees = Employee::whereHas('user', fn ($q) => $q->where('is_active', true))
->whereDoesntHave('user.roles', fn ($q) => $q->where('name', Role::ADMIN_BAHAN_BAKU))
->where(fn ($q) => $q->whereNull('resign_date')->orWhere('resign_date', '>=', $now->toDateString())) ->where(fn ($q) => $q->whereNull('resign_date')->orWhere('resign_date', '>=', $now->toDateString()))
->get(); ->get();

View File

@ -40,11 +40,22 @@ public function handle(): void
return; return;
} }
$year = $yesterday->year; $cuttingDay = 5;
$month = $yesterday->month;
$period = PayrollPeriod::where('year', $year) if ($yesterday->day < $cuttingDay) {
->where('month', $month) $periodMonth = $yesterday->month;
$periodYear = $yesterday->year;
} else {
$periodMonth = $yesterday->month + 1;
$periodYear = $yesterday->year;
if ($periodMonth > 12) {
$periodMonth = 1;
$periodYear++;
}
}
$period = PayrollPeriod::where('year', $periodYear)
->where('month', $periodMonth)
->first(); ->first();
if (! $period) { if (! $period) {

View File

@ -47,9 +47,22 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
public function getCurrentOrCreate(): PayrollPeriod public function getCurrentOrCreate(): PayrollPeriod
{ {
$now = now(); $now = now();
$cuttingDay = 5;
if ($now->day < $cuttingDay) {
$year = $now->year;
$month = $now->month;
} else {
$year = $now->year;
$month = $now->month + 1;
if ($month > 12) {
$month = 1;
$year++;
}
}
return PayrollPeriod::firstOrCreate( return PayrollPeriod::firstOrCreate(
['year' => $now->year, 'month' => $now->month], ['year' => $year, 'month' => $month],
['status' => PayrollPeriodStatus::OPEN] ['status' => PayrollPeriodStatus::OPEN]
); );
} }

View File

@ -5,6 +5,9 @@
use App\Jobs\CleanupOrphanedMediaJob; use App\Jobs\CleanupOrphanedMediaJob;
use Illuminate\Support\Facades\Schedule; use Illuminate\Support\Facades\Schedule;
Schedule::command(GeneratePayrollCommand::class)->monthlyOn(1, '00:00'); Schedule::command(GeneratePayrollCommand::class)
Schedule::job(new CheckAttendancePenaltiesJob)->dailyAt('00:00'); ->daily()
->when(fn () => now()->day === 5)
->at('00:00');
Schedule::job(new CheckAttendancePenaltiesJob)->dailyAt('12:00');
Schedule::job(new CleanupOrphanedMediaJob)->monthlyOn(1, '01:00'); Schedule::job(new CleanupOrphanedMediaJob)->monthlyOn(1, '01:00');