'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; }); } }