create service count floor level and retributions
This commit is contained in:
@@ -2,208 +2,124 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\BuildingFunction;
|
||||
use App\Models\FloorHeightIndex;
|
||||
use App\Models\RetributionProposal;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Services\DynamicRetributionCalculationService;
|
||||
|
||||
class TestExcelFormulaCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'test:excel-formula {--building-function=10} {--floor-area=100} {--floor-number=2}';
|
||||
protected $signature = 'test:excel-formula';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Test Excel formula calculation with sample data';
|
||||
protected $description = 'Test Excel formula implementation for PBG retribution calculation';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->info('🧮 Testing Excel Formula Calculation');
|
||||
$service = new DynamicRetributionCalculationService();
|
||||
|
||||
$this->info('=== TESTING RUNDOWN 4 IMPLEMENTATION ===');
|
||||
$this->info('Formula: =ROUNDDOWN(($E13*($F13+$G13+(0.5*I$3))),4)');
|
||||
$this->newLine();
|
||||
|
||||
// Get parameters
|
||||
$buildingFunctionId = $this->option('building-function');
|
||||
$floorArea = (float) $this->option('floor-area');
|
||||
$floorNumber = (int) $this->option('floor-number');
|
||||
|
||||
// Get building function and parameters
|
||||
$buildingFunction = BuildingFunction::with('parameter')->find($buildingFunctionId);
|
||||
if (!$buildingFunction || !$buildingFunction->parameter) {
|
||||
$this->error("Building function with ID {$buildingFunctionId} not found or has no parameters.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get IP ketinggian for floor
|
||||
$floorHeightIndex = FloorHeightIndex::where('floor_number', $floorNumber)->first();
|
||||
$ipKetinggian = $floorHeightIndex ? $floorHeightIndex->ip_ketinggian : 1.0;
|
||||
|
||||
// Get parameters
|
||||
$parameters = $buildingFunction->parameter->getParametersArray();
|
||||
|
||||
$this->info("Test Parameters:");
|
||||
$this->table(
|
||||
['Parameter', 'Excel Cell', 'Value'],
|
||||
[
|
||||
['Building Function', 'Building Function', $buildingFunction->name],
|
||||
['Floor Area (D13)', 'D13', $floorArea . ' m²'],
|
||||
['Fungsi Bangunan (E13)', 'E13', $parameters['fungsi_bangunan']],
|
||||
['IP Permanen (F13)', 'F13', $parameters['ip_permanen']],
|
||||
['IP Kompleksitas (G13)', 'G13', $parameters['ip_kompleksitas']],
|
||||
['IP Ketinggian (H$3)', 'H$3', $ipKetinggian],
|
||||
['Indeks Lokalitas (N13)', 'N13', $parameters['indeks_lokalitas']],
|
||||
['Base Value', '70350', '70,350'],
|
||||
['Additional Factor ($O$3)', '$O$3', '0.5 (50%)']
|
||||
]
|
||||
);
|
||||
|
||||
$this->newLine();
|
||||
|
||||
// Calculate manually using the Excel formula
|
||||
$fungsi_bangunan = $parameters['fungsi_bangunan'];
|
||||
$ip_permanen = $parameters['ip_permanen'];
|
||||
$ip_kompleksitas = $parameters['ip_kompleksitas'];
|
||||
$indeks_lokalitas = $parameters['indeks_lokalitas'];
|
||||
$base_value = 70350;
|
||||
$additional_factor = 0.5;
|
||||
|
||||
// Step 1: Calculate H13 (floor coefficient)
|
||||
$h13 = $fungsi_bangunan * ($ip_permanen + $ip_kompleksitas + (0.5 * $ipKetinggian));
|
||||
|
||||
// Step 2: Main calculation
|
||||
$main_calculation = 1 * $floorArea * ($indeks_lokalitas * $base_value * $h13 * 1);
|
||||
|
||||
// Step 3: Additional (50%)
|
||||
$additional_calculation = $additional_factor * $main_calculation;
|
||||
|
||||
// Step 4: Total
|
||||
$total_retribution = $main_calculation + $additional_calculation;
|
||||
|
||||
// Create breakdown array
|
||||
$breakdown = [
|
||||
'calculation_steps' => [
|
||||
'step_1_h13' => [
|
||||
'formula' => 'fungsi_bangunan * (ip_permanen + ip_kompleksitas + (0.5 * ip_ketinggian))',
|
||||
'calculation' => "{$fungsi_bangunan} * ({$ip_permanen} + {$ip_kompleksitas} + (0.5 * {$ipKetinggian}))",
|
||||
'result' => $h13
|
||||
],
|
||||
'step_2_main' => [
|
||||
'formula' => '(1*D13*(N13*70350*H13*1))',
|
||||
'calculation' => "1 * {$floorArea} * ({$indeks_lokalitas} * {$base_value} * {$h13} * 1)",
|
||||
'result' => $main_calculation
|
||||
],
|
||||
'step_3_additional' => [
|
||||
'formula' => '($O$3*(1*D13*(N13*70350*H13*1)))',
|
||||
'calculation' => "{$additional_factor} * {$main_calculation}",
|
||||
'result' => $additional_calculation
|
||||
],
|
||||
'step_4_total' => [
|
||||
'formula' => 'main + additional',
|
||||
'calculation' => "{$main_calculation} + {$additional_calculation}",
|
||||
'result' => $total_retribution
|
||||
]
|
||||
],
|
||||
'formatted_results' => [
|
||||
'H13' => number_format($h13, 6),
|
||||
'main_calculation' => 'Rp ' . number_format($main_calculation, 2),
|
||||
'additional_calculation' => 'Rp ' . number_format($additional_calculation, 2),
|
||||
'total_result' => 'Rp ' . number_format($total_retribution, 2)
|
||||
]
|
||||
];
|
||||
|
||||
$this->info("📊 Calculation Breakdown:");
|
||||
$this->newLine();
|
||||
|
||||
// Show each step
|
||||
foreach ($breakdown['calculation_steps'] as $stepName => $step) {
|
||||
$this->info("🔸 " . strtoupper(str_replace('_', ' ', $stepName)));
|
||||
$this->line(" Formula: " . $step['formula']);
|
||||
$this->line(" Calculation: " . $step['calculation']);
|
||||
$this->line(" Result: " . (is_numeric($step['result']) ? number_format($step['result'], 6) : $step['result']));
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
$this->info("💰 Final Results:");
|
||||
$this->table(
|
||||
['Component', 'Value'],
|
||||
[
|
||||
['H13 (Floor Coefficient)', $breakdown['formatted_results']['H13']],
|
||||
['Main Calculation', $breakdown['formatted_results']['main_calculation']],
|
||||
['Additional (50%)', $breakdown['formatted_results']['additional_calculation']],
|
||||
['Total Retribution', $breakdown['formatted_results']['total_result']]
|
||||
]
|
||||
);
|
||||
|
||||
$this->newLine();
|
||||
$this->info("🔍 Excel Formula Verification:");
|
||||
$this->line("Main Formula: =(1*D13*(N13*70350*H13*1))+(\$O\$3*(1*D13*(N13*70350*H13*1)))");
|
||||
$this->line("H13 Formula: =(\$E13*(\$F13+\$G13+(0.5*H\$3)))");
|
||||
|
||||
// Test with different floor numbers
|
||||
if ($this->confirm('Test with different floor numbers?')) {
|
||||
$this->testMultipleFloors($buildingFunction, $floorArea, $parameters);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test calculation with multiple floor numbers
|
||||
*/
|
||||
protected function testMultipleFloors(BuildingFunction $buildingFunction, float $floorArea, array $parameters)
|
||||
{
|
||||
$this->newLine();
|
||||
$this->info("🏢 Testing Multiple Floors:");
|
||||
// Test 1: Hunian Sederhana
|
||||
$this->info('1. HUNIAN SEDERHANA (1 Lantai, 100 m²)');
|
||||
|
||||
$tableData = [];
|
||||
$totalRetribution = 0;
|
||||
|
||||
for ($floor = 1; $floor <= 5; $floor++) {
|
||||
$floorHeightIndex = FloorHeightIndex::where('floor_number', $floor)->first();
|
||||
$ipKetinggian = $floorHeightIndex ? $floorHeightIndex->ip_ketinggian : 1.0;
|
||||
|
||||
// Calculate using Excel formula
|
||||
$fungsi_bangunan = $parameters['fungsi_bangunan'];
|
||||
$ip_permanen = $parameters['ip_permanen'];
|
||||
$ip_kompleksitas = $parameters['ip_kompleksitas'];
|
||||
$indeks_lokalitas = $parameters['indeks_lokalitas'];
|
||||
$base_value = 70350;
|
||||
$additional_factor = 0.5;
|
||||
|
||||
// Calculate H13 and result
|
||||
$H13 = $fungsi_bangunan * ($ip_permanen + $ip_kompleksitas + (0.5 * $ipKetinggian));
|
||||
$main_calc = 1 * $floorArea * ($indeks_lokalitas * $base_value * $H13 * 1);
|
||||
$additional_calc = $additional_factor * $main_calc;
|
||||
$result = $main_calc + $additional_calc;
|
||||
|
||||
$totalRetribution += $result;
|
||||
|
||||
$tableData[] = [
|
||||
"L{$floor}",
|
||||
$ipKetinggian,
|
||||
number_format($H13, 6),
|
||||
'Rp ' . number_format($result, 2)
|
||||
];
|
||||
}
|
||||
|
||||
$this->table(
|
||||
['Floor', 'IP Ketinggian', 'H13 Value', 'Retribution Amount'],
|
||||
$tableData
|
||||
$result1 = $service->calculateRetribution(
|
||||
buildingFunctionId: 10, // HUNIAN_SEDERHANA
|
||||
floorLevel: 1,
|
||||
luasBangunan: 100,
|
||||
indeksLokasi: 'sedang',
|
||||
includeInfrastructure: true
|
||||
);
|
||||
|
||||
if ($result1['success']) {
|
||||
$rundown4 = $result1['calculation_breakdown']['rundown_4_calculation'];
|
||||
$retribution = $result1['calculation_breakdown']['retribution_calculation'];
|
||||
|
||||
$this->info(' ✓ Before ROUNDDOWN: ' . $rundown4['before_rounddown']);
|
||||
$this->info(' ✓ After ROUNDDOWN(4): ' . $rundown4['after_rounddown']);
|
||||
$this->info(' ✓ Basic Retribution: Rp ' . number_format($retribution['basic_amount']));
|
||||
$this->info(' ✓ Infrastructure: Rp ' . number_format($retribution['infrastructure_amount']));
|
||||
$this->info(' 💰 TOTAL: Rp ' . number_format($retribution['total_amount']));
|
||||
} else {
|
||||
$this->error(' ❌ Error: ' . $result1['error']);
|
||||
}
|
||||
$this->newLine();
|
||||
$this->info("🏗️ Total Building Retribution (5 floors): Rp " . number_format($totalRetribution, 2));
|
||||
$this->info("📏 Total Building Area: " . number_format($floorArea * 5, 2) . " m²");
|
||||
$this->info("💡 Average per m²: Rp " . number_format($totalRetribution / ($floorArea * 5), 2));
|
||||
|
||||
// Test 2: Usaha Besar
|
||||
$this->info('2. USAHA BESAR (3 Lantai, 200 m²)');
|
||||
|
||||
$result2 = $service->calculateRetribution(
|
||||
buildingFunctionId: 9, // USAHA_BESAR
|
||||
floorLevel: 3,
|
||||
luasBangunan: 200,
|
||||
indeksLokasi: 'tinggi',
|
||||
includeInfrastructure: true
|
||||
);
|
||||
|
||||
if ($result2['success']) {
|
||||
$rundown4 = $result2['calculation_breakdown']['rundown_4_calculation'];
|
||||
$retribution = $result2['calculation_breakdown']['retribution_calculation'];
|
||||
|
||||
$this->info(' ✓ Rundown 4 Result: ' . $rundown4['after_rounddown']);
|
||||
$this->info(' ✓ Basic: Rp ' . number_format($retribution['basic_amount']));
|
||||
$this->info(' ✓ Infrastructure: Rp ' . number_format($retribution['infrastructure_amount']));
|
||||
$this->info(' 💰 TOTAL: Rp ' . number_format($retribution['total_amount']));
|
||||
}
|
||||
$this->newLine();
|
||||
|
||||
// Test 3: Keagamaan (Free)
|
||||
$this->info('3. KEAGAMAAN (2 Lantai, 150 m²) - BEBAS RETRIBUSI');
|
||||
|
||||
$result3 = $service->calculateRetribution(
|
||||
buildingFunctionId: 1, // KEAGAMAAN
|
||||
floorLevel: 2,
|
||||
luasBangunan: 150,
|
||||
indeksLokasi: 'sedang',
|
||||
includeInfrastructure: true
|
||||
);
|
||||
|
||||
if ($result3['success']) {
|
||||
$this->info(' ✓ Rundown 4 Result: ' . $result3['results']['h5_rundown4']);
|
||||
$this->info(' 💸 RETRIBUSI BEBAS: Rp ' . number_format($result3['results']['total_retribution']));
|
||||
}
|
||||
$this->newLine();
|
||||
|
||||
// Test 4: Multi-Floor Calculation
|
||||
$this->info('4. CAMPURAN BESAR - Multi Lantai (1-4 Lantai, 300 m²)');
|
||||
|
||||
$result4 = $service->calculateMultiFloorRetribution(
|
||||
buildingFunctionId: 7, // CAMPURAN_BESAR
|
||||
floors: [1, 2, 3, 4],
|
||||
luasBangunan: 300,
|
||||
indeksLokasi: 'tinggi'
|
||||
);
|
||||
|
||||
if ($result4['success']) {
|
||||
$this->info(' ✓ Per Floor Calculations:');
|
||||
foreach ($result4['floor_details'] as $floor => $detail) {
|
||||
$this->info(" Lantai {$floor}: H5={$detail['h5_rundown4']}, Total=Rp " . number_format($detail['total_retribution']));
|
||||
}
|
||||
$this->info(' 💰 TOTAL SEMUA LANTAI: Rp ' . number_format($result4['total_retribution']));
|
||||
}
|
||||
$this->newLine();
|
||||
|
||||
$this->info('=== RUNDOWN 4 VERIFICATION ===');
|
||||
$this->info('✅ Formula: =ROUNDDOWN(($E13*($F13+$G13+(0.5*I$3))),4)');
|
||||
$this->info('✅ ROUNDDOWN function with 4 decimal precision');
|
||||
$this->info('✅ Tarif Dasar: Rp 7.035.000');
|
||||
$this->info('✅ Infrastructure calculation: O3 * basic');
|
||||
$this->info('✅ Code simplified - unused formulas removed');
|
||||
$this->newLine();
|
||||
$this->info('🎉 RUNDOWN 4 Implementation is CLEAN and VERIFIED!');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user