SIPDAM/samooapk/laravel/app/Models/Penggajian.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;
});
}
}