restructure retribution calculations table

This commit is contained in:
arifal hidayat
2025-06-18 22:53:44 +07:00
parent df70a47bd1
commit 4c3443c2d6
12 changed files with 1548 additions and 0 deletions

View File

@@ -0,0 +1,291 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\BuildingType;
use App\Models\RetributionIndex;
use App\Models\HeightIndex;
use App\Models\RetributionConfig;
use App\Models\RetributionCalculation;
use App\Services\RetributionCalculatorService;
class TestRetributionData extends Command
{
protected $signature = 'retribution:data
{--save : Save calculation results to database}
{--show : Show existing data and relations}
{--clear : Clear calculation history}';
protected $description = 'Test retribution data storage and display database relations';
protected $calculatorService;
public function __construct(RetributionCalculatorService $calculatorService)
{
parent::__construct();
$this->calculatorService = $calculatorService;
}
public function handle()
{
$this->info('🗄️ SISTEM TEST DATA & RELASI RETRIBUSI PBG');
$this->info('=' . str_repeat('=', 55));
if ($this->option('clear')) {
$this->clearCalculationHistory();
return;
}
if ($this->option('show')) {
$this->showExistingData();
return;
}
if ($this->option('save')) {
$this->saveTestCalculations();
}
$this->showDatabaseStructure();
$this->showSampleData();
$this->showRelations();
}
protected function saveTestCalculations()
{
$this->info('💾 MENYIMPAN SAMPLE CALCULATIONS...');
$this->line('');
$testCases = [
['type_code' => 'KEAGAMAAN', 'area' => 200, 'floor' => 1],
['type_code' => 'SOSBUDAYA', 'area' => 150, 'floor' => 2],
['type_code' => 'CAMP_KECIL', 'area' => 1, 'floor' => 1],
['type_code' => 'UMKM', 'area' => 100, 'floor' => 2],
['type_code' => 'HUN_SEDH', 'area' => 80, 'floor' => 1],
['type_code' => 'USH_BESAR', 'area' => 500, 'floor' => 3],
];
foreach ($testCases as $case) {
$buildingType = BuildingType::where('code', $case['type_code'])->first();
if (!$buildingType) {
$this->warn("⚠️ Building type {$case['type_code']} not found");
continue;
}
$result = $this->calculatorService->calculate(
$buildingType->id,
$case['floor'],
$case['area']
);
// Save to database
RetributionCalculation::create([
'calculation_id' => 'TST' . now()->format('ymdHis') . rand(10, 99),
'building_type_id' => $buildingType->id,
'floor_number' => $case['floor'],
'building_area' => $case['area'],
'retribution_amount' => $result['total_retribution'],
'calculation_detail' => json_encode($result),
'calculated_at' => now()
]);
$this->info("✅ Saved: {$buildingType->name} - {$case['area']}m² - {$case['floor']} lantai - Rp " . number_format($result['total_retribution']));
}
$this->line('');
$this->info('💾 Sample calculations saved successfully!');
$this->line('');
}
protected function showExistingData()
{
$this->info('📊 DATA YANG TERSIMPAN DI DATABASE');
$this->info('=' . str_repeat('=', 40));
$calculations = RetributionCalculation::with('buildingType')
->orderBy('created_at', 'desc')
->limit(10)
->get();
if ($calculations->isEmpty()) {
$this->warn('❌ Tidak ada data calculation yang tersimpan');
$this->info('💡 Gunakan --save untuk menyimpan sample data');
return;
}
$headers = ['ID', 'Building Type', 'Area', 'Floor', 'Amount', 'Created'];
$rows = [];
foreach ($calculations as $calc) {
$rows[] = [
substr($calc->calculation_id, -8),
$calc->buildingType->name ?? 'N/A',
$calc->building_area . ' m²',
$calc->floor_number,
'Rp ' . number_format($calc->retribution_amount),
$calc->created_at->format('d/m H:i')
];
}
$this->table($headers, $rows);
}
protected function clearCalculationHistory()
{
$count = RetributionCalculation::count();
if ($count === 0) {
$this->info(' Tidak ada data calculation untuk dihapus');
return;
}
if ($this->confirm("🗑️ Hapus {$count} calculation records?")) {
RetributionCalculation::truncate();
$this->info("{$count} calculation records berhasil dihapus");
}
}
protected function showDatabaseStructure()
{
$this->info('🏗️ STRUKTUR DATABASE RETRIBUSI');
$this->info('=' . str_repeat('=', 35));
$tables = [
'building_types' => 'Hierarki dan metadata building types',
'retribution_indices' => 'Parameter perhitungan (coefficient, IP, dll)',
'height_indices' => 'Koefisien tinggi berdasarkan lantai',
'retribution_configs' => 'Konfigurasi global (base value, dll)',
'retribution_calculations' => 'History perhitungan dan hasil'
];
foreach ($tables as $table => $description) {
$this->line("📋 <info>{$table}</info>: {$description}");
}
$this->line('');
}
protected function showSampleData()
{
$this->info('📋 SAMPLE DATA DARI SETIAP TABEL');
$this->info('=' . str_repeat('=', 35));
// Building Types
$this->line('<comment>🏢 BUILDING TYPES:</comment>');
$buildingTypes = BuildingType::select('id', 'code', 'name', 'level', 'is_free')
->orderBy('level')
->orderBy('name')
->get();
$headers = ['ID', 'Code', 'Name', 'Level', 'Free'];
$rows = [];
foreach ($buildingTypes->take(5) as $type) {
$rows[] = [
$type->id,
$type->code,
substr($type->name, 0, 25) . '...',
$type->level,
$type->is_free ? '✅' : '❌'
];
}
$this->table($headers, $rows);
// Retribution Indices
$this->line('<comment>📊 RETRIBUTION INDICES:</comment>');
$indices = RetributionIndex::with('buildingType')
->select('building_type_id', 'coefficient', 'ip_permanent', 'ip_complexity', 'locality_index')
->get();
$headers = ['Building Type', 'Coefficient', 'IP Permanent', 'IP Complexity', 'Locality'];
$rows = [];
foreach ($indices->take(5) as $index) {
$rows[] = [
$index->buildingType->code ?? 'N/A',
number_format($index->coefficient, 4),
number_format($index->ip_permanent, 4),
number_format($index->ip_complexity, 4),
number_format($index->locality_index, 4)
];
}
$this->table($headers, $rows);
// Height Indices
$this->line('<comment>🏗️ HEIGHT INDICES:</comment>');
$heights = HeightIndex::orderBy('floor_number')->get();
$headers = ['Floor', 'Height Index'];
$rows = [];
foreach ($heights as $height) {
$rows[] = [
$height->floor_number,
number_format($height->height_index, 4)
];
}
$this->table($headers, $rows);
// Retribution Configs
$this->line('<comment>⚙️ RETRIBUTION CONFIGS:</comment>');
$configs = RetributionConfig::all();
$headers = ['Key', 'Value', 'Description'];
$rows = [];
foreach ($configs as $config) {
$rows[] = [
$config->key,
$config->value,
substr($config->description ?? '', 0, 30) . '...'
];
}
$this->table($headers, $rows);
}
protected function showRelations()
{
$this->info('🔗 RELASI ANTAR TABEL');
$this->info('=' . str_repeat('=', 25));
// Test relations dengan sample data
$buildingType = BuildingType::with(['indices', 'calculations'])
->where('code', 'UMKM')
->first();
if (!$buildingType) {
$this->warn('⚠️ Sample building type tidak ditemukan');
return;
}
$this->line("<comment>🏢 Building Type: {$buildingType->name}</comment>");
$this->line(" 📋 Code: {$buildingType->code}");
$this->line(" 📊 Level: {$buildingType->level}");
$this->line(" 🆓 Free: " . ($buildingType->is_free ? 'Ya' : 'Tidak'));
// Show indices relation
if ($buildingType->indices) {
$index = $buildingType->indices;
$this->line(" <comment>📊 Retribution Index:</comment>");
$this->line(" 💰 Coefficient: " . number_format($index->coefficient, 4));
$this->line(" 🏗️ IP Permanent: " . number_format($index->ip_permanent, 4));
$this->line(" 🔧 IP Complexity: " . number_format($index->ip_complexity, 4));
$this->line(" 📍 Locality Index: " . number_format($index->locality_index, 4));
}
// Show calculations relation
$calculationsCount = $buildingType->calculations()->count();
$this->line(" <comment>📈 Calculations: {$calculationsCount} records</comment>");
if ($calculationsCount > 0) {
$latestCalc = $buildingType->calculations()->latest()->first();
$this->line(" 📅 Latest: " . $latestCalc->created_at->format('d/m/Y H:i'));
$this->line(" 💰 Amount: Rp " . number_format($latestCalc->retribution_amount));
}
$this->line('');
$this->info('🎯 KESIMPULAN RELASI:');
$this->line(' • BuildingType hasOne RetributionIndex');
$this->line(' • BuildingType hasMany RetributionCalculations');
$this->line(' • RetributionCalculation belongsTo BuildingType');
$this->line(' • HeightIndex independent (digunakan berdasarkan floor_number)');
$this->line(' • RetributionConfig global settings');
}
}