383 lines
9.4 KiB
PHP
383 lines
9.4 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
use Carbon\Carbon;
|
|
|
|
class Penggajian extends Model
|
|
{
|
|
// use HasFactory, SoftDeletes;
|
|
|
|
/**
|
|
* Get nama bulan dari angka 1-12
|
|
*/
|
|
public static function getNamaBulan($angka)
|
|
{
|
|
$bulan = [
|
|
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 $bulan[(int)$angka] ?? 'N/A';
|
|
}
|
|
|
|
/**
|
|
* The table associated with the model.
|
|
*/
|
|
protected $table = 'penggajians';
|
|
|
|
/**
|
|
* The primary key for the model.
|
|
*/
|
|
protected $primaryKey = 'id_penggajian';
|
|
|
|
/**
|
|
* The attributes that are mass assignable.
|
|
*/
|
|
protected $fillable = [
|
|
'id_teknisi',
|
|
'periode_bulan',
|
|
'periode_tahun',
|
|
'tanggal_penggajian',
|
|
'total_ongkos_pekerjaan',
|
|
'jumlah_penugasan_selesai',
|
|
'jumlah_hari_kerja',
|
|
'total_kasbon',
|
|
'biaya_makan',
|
|
'total_potongan',
|
|
'gaji_bersih',
|
|
'status_pembayaran',
|
|
'metode_pembayaran',
|
|
'tanggal_dibayar',
|
|
'bukti_pembayaran',
|
|
'catatan',
|
|
];
|
|
|
|
/**
|
|
* The attributes that should be cast.
|
|
*/
|
|
protected $casts = [
|
|
'tanggal_penggajian' => 'date',
|
|
'jumlah_hari_kerja' => 'integer',
|
|
'total_ongkos_pekerjaan' => 'decimal:2',
|
|
'total_kasbon' => 'decimal:2',
|
|
'biaya_makan' => 'decimal:2',
|
|
'total_potongan' => 'decimal:2',
|
|
'gaji_bersih' => 'decimal:2',
|
|
'created_at' => 'datetime',
|
|
'updated_at' => 'datetime',
|
|
'deleted_at' => 'datetime',
|
|
];
|
|
|
|
/**
|
|
* The attributes that should be hidden for arrays.
|
|
*/
|
|
protected $hidden = [
|
|
'deleted_at',
|
|
];
|
|
|
|
/**
|
|
* Status pembayaran constants
|
|
*/
|
|
const STATUS_BELUM_BAYAR = 'belum_bayar';
|
|
const STATUS_SUDAH_BAYAR = 'sudah_bayar';
|
|
|
|
/**
|
|
* Get all available status pembayaran
|
|
*/
|
|
public static function getStatusPembayaran()
|
|
{
|
|
return [
|
|
self::STATUS_BELUM_BAYAR => 'Belum Bayar',
|
|
self::STATUS_SUDAH_BAYAR => 'Sudah Bayar',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Relationship with Teknisi
|
|
*/
|
|
public function teknisi()
|
|
{
|
|
return $this->belongsTo(Teknisi::class, 'id_teknisi', 'id_teknisi');
|
|
}
|
|
|
|
/**
|
|
* Relationship with DetailPenggajian
|
|
*/
|
|
public function detailPenggajian()
|
|
{
|
|
return $this->hasMany(DetailPenggajian::class, 'id_penggajian', 'id_penggajian');
|
|
}
|
|
|
|
/**
|
|
* Scope for filtering by periode
|
|
*/
|
|
public function scopeByPeriode($query, $bulan = null, $tahun = null)
|
|
{
|
|
if ($bulan) {
|
|
$query->where('periode_bulan', $bulan);
|
|
}
|
|
if ($tahun) {
|
|
$query->where('periode_tahun', $tahun);
|
|
}
|
|
return $query;
|
|
}
|
|
|
|
/**
|
|
* Scope for filtering by status pembayaran
|
|
*/
|
|
public function scopeByStatus($query, $status)
|
|
{
|
|
return $query->where('status_pembayaran', $status);
|
|
}
|
|
|
|
/**
|
|
* Scope for belum bayar
|
|
*/
|
|
public function scopeBelumBayar($query)
|
|
{
|
|
return $query->where('status_pembayaran', self::STATUS_BELUM_BAYAR);
|
|
}
|
|
|
|
/**
|
|
* Scope for sudah bayar
|
|
*/
|
|
public function scopeSudahBayar($query)
|
|
{
|
|
return $query->where('status_pembayaran', self::STATUS_SUDAH_BAYAR);
|
|
}
|
|
|
|
/**
|
|
* Scope for current month
|
|
*/
|
|
public function scopeCurrentMonth($query)
|
|
{
|
|
return $query->where('periode_bulan', date('n'))
|
|
->where('periode_tahun', date('Y'));
|
|
}
|
|
|
|
/**
|
|
* Scope for latest periode
|
|
*/
|
|
public function scopeLatestPeriode($query)
|
|
{
|
|
return $query->orderBy('periode_tahun', 'desc')
|
|
->orderBy('periode_bulan', 'desc');
|
|
}
|
|
|
|
/**
|
|
* Get formatted periode
|
|
*/
|
|
public function getFormattedPeriodeAttribute()
|
|
{
|
|
$bulan = Carbon::create()->month($this->periode_bulan)->format('F');
|
|
return $bulan . ' ' . $this->periode_tahun;
|
|
}
|
|
|
|
/**
|
|
* Get periode short format
|
|
*/
|
|
public function getPeriodeShortAttribute()
|
|
{
|
|
$bulan = Carbon::create()->month($this->periode_bulan)->format('M');
|
|
return $bulan . ' ' . $this->periode_tahun;
|
|
}
|
|
|
|
/**
|
|
* Get status pembayaran label
|
|
*/
|
|
public function getStatusLabelAttribute()
|
|
{
|
|
$statuses = self::getStatusPembayaran();
|
|
return $statuses[$this->status_pembayaran] ?? $this->status_pembayaran;
|
|
}
|
|
|
|
/**
|
|
* Get status badge class
|
|
*/
|
|
public function getStatusBadgeClassAttribute()
|
|
{
|
|
switch ($this->status_pembayaran) {
|
|
case self::STATUS_SUDAH_BAYAR:
|
|
return 'bg-success';
|
|
case self::STATUS_BELUM_BAYAR:
|
|
default:
|
|
return 'bg-warning';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if already paid
|
|
*/
|
|
public function isPaid()
|
|
{
|
|
return $this->status_pembayaran === self::STATUS_SUDAH_BAYAR;
|
|
}
|
|
|
|
/**
|
|
* Check if not paid yet
|
|
*/
|
|
public function isUnpaid()
|
|
{
|
|
return $this->status_pembayaran === self::STATUS_BELUM_BAYAR;
|
|
}
|
|
|
|
/**
|
|
* Mark as paid
|
|
*/
|
|
public function markAsPaid()
|
|
{
|
|
$this->update([
|
|
'status_pembayaran' => self::STATUS_SUDAH_BAYAR
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Mark as unpaid
|
|
*/
|
|
public function markAsUnpaid()
|
|
{
|
|
$this->update([
|
|
'status_pembayaran' => self::STATUS_BELUM_BAYAR
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Calculate total from detail penggajian
|
|
*/
|
|
public function calculateTotals()
|
|
{
|
|
$details = $this->detailPenggajian;
|
|
|
|
$totals = [
|
|
'subtotal' => $details->sum('subtotal'),
|
|
'total_unit' => $details->sum('jumlah_unit'),
|
|
];
|
|
|
|
return $totals;
|
|
}
|
|
|
|
/**
|
|
* Get formatted currency attributes
|
|
*/
|
|
public function getFormattedGajiKotorAttribute()
|
|
{
|
|
return 'Rp ' . number_format($this->total_ongkos_pekerjaan, 0, ',', '.');
|
|
}
|
|
|
|
public function getFormattedBiayaMakanAttribute()
|
|
{
|
|
return 'Rp ' . number_format($this->biaya_makan, 0, ',', '.');
|
|
}
|
|
|
|
public function getFormattedTotalKasbonAttribute()
|
|
{
|
|
return 'Rp ' . number_format($this->total_kasbon, 0, ',', '.');
|
|
}
|
|
|
|
public function getFormattedGajiBersihAttribute()
|
|
{
|
|
return 'Rp ' . number_format($this->gaji_bersih, 0, ',', '.');
|
|
}
|
|
|
|
/**
|
|
* Get potongan (total kasbon)
|
|
*/
|
|
public function getPotonganAttribute()
|
|
{
|
|
return $this->total_kasbon;
|
|
}
|
|
|
|
/**
|
|
* Get formatted potongan
|
|
*/
|
|
public function getFormattedPotonganAttribute()
|
|
{
|
|
return 'Rp ' . number_format($this->potongan, 0, ',', '.');
|
|
}
|
|
|
|
/**
|
|
* Static method to get summary by periode
|
|
*/
|
|
public static function getSummaryByPeriode($bulan = null, $tahun = null, $status = null)
|
|
{
|
|
$query = self::with('teknisi');
|
|
|
|
if ($bulan) {
|
|
$query->where('periode_bulan', $bulan);
|
|
}
|
|
if ($tahun) {
|
|
$query->where('periode_tahun', $tahun);
|
|
}
|
|
if ($status) {
|
|
$query->where('status_pembayaran', $status);
|
|
}
|
|
|
|
$data = $query->get();
|
|
|
|
return [
|
|
'total_teknisi' => $data->count(),
|
|
'total_gaji' => $data->sum('total_ongkos_pekerjaan'),
|
|
'total_kasbon' => $data->sum('total_kasbon'),
|
|
'total_biaya_makan' => $data->sum('biaya_makan'),
|
|
'gaji_bersih' => $data->sum('gaji_bersih'),
|
|
'belum_bayar' => $data->where('status_pembayaran', self::STATUS_BELUM_BAYAR)->count(),
|
|
'sudah_bayar' => $data->where('status_pembayaran', self::STATUS_SUDAH_BAYAR)->count(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Static method to check if periode already exists for teknisi
|
|
*/
|
|
public static function isPeriodeExists($idTeknisi, $bulan, $tahun)
|
|
{
|
|
return self::where('id_teknisi', $idTeknisi)
|
|
->where('periode_bulan', $bulan)
|
|
->where('periode_tahun', $tahun)
|
|
->exists();
|
|
}
|
|
|
|
/**
|
|
* Static method to get latest periode
|
|
*/
|
|
public static function getLatestPeriode()
|
|
{
|
|
$latest = self::orderBy('periode_tahun', 'desc')
|
|
->orderBy('periode_bulan', 'desc')
|
|
->first();
|
|
|
|
if (!$latest) {
|
|
return [
|
|
'bulan' => date('n'),
|
|
'tahun' => date('Y')
|
|
];
|
|
}
|
|
|
|
return [
|
|
'bulan' => $latest->periode_bulan,
|
|
'tahun' => $latest->periode_tahun
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Boot method
|
|
*/
|
|
protected static function boot()
|
|
{
|
|
parent::boot();
|
|
|
|
// Auto calculate gaji_bersih before saving
|
|
static::saving(function ($penggajian) {
|
|
$ongkos = $penggajian->total_ongkos_pekerjaan ?? 0;
|
|
$makan = $penggajian->biaya_makan ?? 0;
|
|
$potongan = $penggajian->total_potongan ?? 0;
|
|
|
|
// Gaji Bersih = Ongkos - Uang Makan - Potongan Kasbon
|
|
// (Uang makan sekarang dihitung sebagai potongan)
|
|
$penggajian->gaji_bersih = $ongkos - $makan - $potongan;
|
|
});
|
|
}
|
|
} |