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("📋 {$table}: {$description}"); } $this->line(''); } protected function showSampleData() { $this->info('📋 SAMPLE DATA DARI SETIAP TABEL'); $this->info('=' . str_repeat('=', 35)); // Building Types $this->line('🏢 BUILDING TYPES:'); $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('📊 RETRIBUTION INDICES:'); $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('🏗️ HEIGHT INDICES:'); $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('⚙️ RETRIBUTION CONFIGS:'); $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("🏢 Building Type: {$buildingType->name}"); $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(" 📊 Retribution Index:"); $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(" 📈 Calculations: {$calculationsCount} records"); 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'); } }