'decimal:2', 'retribution_amount' => 'decimal:2', 'calculation_detail' => 'array', 'calculated_at' => 'timestamp', 'floor_number' => 'integer', ]; /** * Get the building type */ public function buildingType(): BelongsTo { return $this->belongsTo(BuildingType::class); } /** * Get all calculable assignments */ public function calculableRetributions(): HasMany { return $this->hasMany(CalculableRetribution::class); } /** * Get active assignments only */ public function activeAssignments(): HasMany { return $this->hasMany(CalculableRetribution::class)->where('is_active', true); } /** * Generate unique calculation ID */ public static function generateCalculationId(): string { return 'CALC-' . date('Ymd') . '-' . str_pad(mt_rand(1, 9999), 4, '0', STR_PAD_LEFT); } /** * Boot method to auto-generate calculation_id */ protected static function boot() { parent::boot(); static::creating(function ($model) { if (empty($model->calculation_id)) { $model->calculation_id = self::generateCalculationId(); } if (empty($model->calculated_at)) { $model->calculated_at = now(); } }); } /** * Check if calculation is being used */ public function isInUse(): bool { return $this->activeAssignments()->exists(); } /** * Get calculation summary */ public function getSummary(): array { return [ 'calculation_id' => $this->calculation_id, 'building_type' => $this->buildingType->name ?? 'Unknown', 'floor_number' => $this->floor_number, 'building_area' => $this->building_area, 'retribution_amount' => $this->retribution_amount, 'calculated_at' => $this->calculated_at->format('Y-m-d H:i:s'), 'in_use' => $this->isInUse(), ]; } /** * Create new calculation */ public static function createCalculation( int $buildingTypeId, int $floorNumber, float $buildingArea, float $retributionAmount, array $calculationDetail ): self { return self::create([ 'calculation_id' => self::generateCalculationId(), 'building_type_id' => $buildingTypeId, 'floor_number' => $floorNumber, 'building_area' => $buildingArea, 'retribution_amount' => $retributionAmount, 'calculation_detail' => $calculationDetail, 'calculated_at' => Carbon::now() ]); } /** * Get formatted retribution amount */ public function getFormattedAmount(): string { return 'Rp ' . number_format($this->retribution_amount, 2, ',', '.'); } /** * Get calculation breakdown */ public function getCalculationBreakdown(): array { return $this->calculation_detail ?? []; } }