168 lines
4.1 KiB
PHP
168 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Carbon\Carbon;
|
|
|
|
class KpiAchievement extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $fillable = [
|
|
'user_id',
|
|
'kpi_target_id',
|
|
'target_value',
|
|
'actual_value',
|
|
'achievement_percentage',
|
|
'year',
|
|
'month',
|
|
'notes'
|
|
];
|
|
|
|
protected $casts = [
|
|
'achievement_percentage' => 'decimal:2',
|
|
'year' => 'integer',
|
|
'month' => 'integer'
|
|
];
|
|
|
|
protected $attributes = [
|
|
'actual_value' => 0,
|
|
'achievement_percentage' => 0
|
|
];
|
|
|
|
/**
|
|
* Get the user that owns the achievement
|
|
*/
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class);
|
|
}
|
|
|
|
/**
|
|
* Get the KPI target for this achievement
|
|
*/
|
|
public function kpiTarget(): BelongsTo
|
|
{
|
|
return $this->belongsTo(KpiTarget::class);
|
|
}
|
|
|
|
/**
|
|
* Scope to get achievements for specific year and month
|
|
*/
|
|
public function scopeForPeriod($query, $year, $month)
|
|
{
|
|
return $query->where('year', $year)->where('month', $month);
|
|
}
|
|
|
|
/**
|
|
* Scope to get achievements for current month
|
|
*/
|
|
public function scopeCurrentMonth($query)
|
|
{
|
|
return $query->where('year', now()->year)->where('month', now()->month);
|
|
}
|
|
|
|
/**
|
|
* Scope to get achievements within year range
|
|
*/
|
|
public function scopeWithinYearRange($query, $startYear, $endYear)
|
|
{
|
|
return $query->whereBetween('year', [$startYear, $endYear]);
|
|
}
|
|
|
|
/**
|
|
* Scope to get achievements for specific user
|
|
*/
|
|
public function scopeForUser($query, $userId)
|
|
{
|
|
return $query->where('user_id', $userId);
|
|
}
|
|
|
|
/**
|
|
* Get achievement status
|
|
*/
|
|
public function getStatusAttribute(): string
|
|
{
|
|
if ($this->achievement_percentage >= 100) {
|
|
return 'exceeded';
|
|
} elseif ($this->achievement_percentage >= 80) {
|
|
return 'good';
|
|
} elseif ($this->achievement_percentage >= 60) {
|
|
return 'fair';
|
|
} else {
|
|
return 'poor';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get status color for display
|
|
*/
|
|
public function getStatusColorAttribute(): string
|
|
{
|
|
return match($this->status) {
|
|
'exceeded' => 'success',
|
|
'good' => 'info',
|
|
'fair' => 'warning',
|
|
'poor' => 'danger',
|
|
default => 'secondary'
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get period display name (e.g., "Januari 2024")
|
|
*/
|
|
public function getPeriodDisplayName(): string
|
|
{
|
|
$monthNames = [
|
|
1 => 'Januari', 2 => 'Februari', 3 => 'Maret', 4 => 'April',
|
|
5 => 'Mei', 6 => 'Juni', 7 => 'Juli', 8 => 'Agustus',
|
|
9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Desember'
|
|
];
|
|
|
|
return $monthNames[$this->month] . ' ' . $this->year;
|
|
}
|
|
|
|
/**
|
|
* Get period start date
|
|
*/
|
|
public function getPeriodStartDate(): Carbon
|
|
{
|
|
return Carbon::createFromDate($this->year, $this->month, 1);
|
|
}
|
|
|
|
/**
|
|
* Get period end date
|
|
*/
|
|
public function getPeriodEndDate(): Carbon
|
|
{
|
|
return Carbon::createFromDate($this->year, $this->month, 1)->endOfMonth();
|
|
}
|
|
|
|
/**
|
|
* Get target value (from stored value or from relation)
|
|
*/
|
|
public function getTargetValueAttribute(): int
|
|
{
|
|
// Return stored target value if available, otherwise get from relation
|
|
return $this->target_value ?? $this->kpiTarget?->target_value ?? 0;
|
|
}
|
|
|
|
/**
|
|
* Get current target value from relation (for comparison)
|
|
*/
|
|
public function getCurrentTargetValueAttribute(): int
|
|
{
|
|
return $this->kpiTarget?->target_value ?? 0;
|
|
}
|
|
|
|
/**
|
|
* Check if stored target value differs from current target value
|
|
*/
|
|
public function hasTargetValueChanged(): bool
|
|
{
|
|
return $this->target_value !== $this->current_target_value;
|
|
}
|
|
}
|