add spatial plannings retribution calculations

This commit is contained in:
arifal hidayat
2025-06-18 02:54:41 +07:00
parent 6946fa7074
commit fc54e20fa4
29 changed files with 2926 additions and 416 deletions

View File

@@ -0,0 +1,187 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class RetributionProposal extends Model
{
use HasFactory;
protected $fillable = [
'spatial_planning_id',
'building_function_id',
'retribution_formula_id',
'proposal_number',
'floor_number',
'floor_area',
'total_building_area',
'ip_ketinggian',
'floor_retribution_amount',
'total_retribution_amount',
'calculation_parameters',
'calculation_breakdown',
'notes',
'calculated_at'
];
protected $casts = [
'floor_area' => 'decimal:6',
'total_building_area' => 'decimal:6',
'ip_ketinggian' => 'decimal:6',
'floor_retribution_amount' => 'decimal:2',
'total_retribution_amount' => 'decimal:2',
'calculation_parameters' => 'array',
'calculation_breakdown' => 'array',
'calculated_at' => 'datetime'
];
/**
* Relationship with SpatialPlanning
*/
public function spatialPlanning(): BelongsTo
{
return $this->belongsTo(SpatialPlanning::class);
}
/**
* Relationship with BuildingFunction
*/
public function buildingFunction(): BelongsTo
{
return $this->belongsTo(BuildingFunction::class);
}
/**
* Relationship with RetributionFormula
*/
public function retributionFormula(): BelongsTo
{
return $this->belongsTo(RetributionFormula::class);
}
/**
* Generate proposal number
*/
public static function generateProposalNumber(): string
{
$year = now()->format('Y');
$month = now()->format('m');
// Use max ID + 1 to avoid duplicates when records are deleted
$maxId = static::whereYear('created_at', now()->year)
->whereMonth('created_at', now()->month)
->max('id') ?? 0;
$nextNumber = $maxId + 1;
// Fallback: if still duplicate, use timestamp
$proposalNumber = sprintf('RP-%s%s-%04d', $year, $month, $nextNumber);
// Check if exists and increment until unique
$counter = $nextNumber;
while (static::where('proposal_number', $proposalNumber)->exists()) {
$counter++;
$proposalNumber = sprintf('RP-%s%s-%04d', $year, $month, $counter);
}
return $proposalNumber;
}
/**
* Get formatted floor retribution amount
*/
public function getFormattedFloorAmountAttribute(): string
{
return 'Rp ' . number_format($this->floor_retribution_amount, 0, ',', '.');
}
/**
* Get formatted total retribution amount
*/
public function getFormattedTotalAmountAttribute(): string
{
return 'Rp ' . number_format($this->total_retribution_amount, 0, ',', '.');
}
/**
* Get calculation breakdown for specific parameter
*/
public function getCalculationBreakdownFor(string $parameter)
{
return $this->calculation_breakdown[$parameter] ?? null;
}
/**
* Get parameter value
*/
public function getParameterValue(string $parameter)
{
return $this->calculation_parameters[$parameter] ?? null;
}
/**
* Scope for filtering by building function
*/
public function scopeByBuildingFunction($query, int $buildingFunctionId)
{
return $query->where('building_function_id', $buildingFunctionId);
}
/**
* Scope for filtering by spatial planning
*/
public function scopeBySpatialPlanning($query, int $spatialPlanningId)
{
return $query->where('spatial_planning_id', $spatialPlanningId);
}
/**
* Get total retribution amount for multiple proposals
*/
public static function getTotalAmount($proposals = null): float
{
if ($proposals) {
return $proposals->sum('total_retribution_amount');
}
return static::sum('total_retribution_amount');
}
/**
* Get basic statistics
*/
public static function getBasicStats(): array
{
return [
'total_count' => static::count(),
'total_amount' => static::sum('total_retribution_amount'),
'average_amount' => static::avg('total_retribution_amount'),
];
}
/**
* Boot method to generate proposal number
*/
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
if (empty($model->proposal_number)) {
$model->proposal_number = static::generateProposalNumber();
}
if (empty($model->calculated_at)) {
$model->calculated_at = now();
}
});
}
}