getParameterValues($buildingFunctionId, $floorLevel, $indeksLokasi); // Step 1: Calculate Rundown 4 per floor value $h5 = $this->calculateRundown4($parameters); // Step 2: Calculate basic retribution $basicRetribution = $parameters['koefisien_dasar'] * $luasBangunan * ($parameters['indeks_lokalitas'] * $parameters['tarif_dasar'] * $h5 * $parameters['koefisien_dasar']); // Step 3: Calculate infrastructure (optional) $infrastructureAmount = 0; $totalRetribution = $basicRetribution; if ($includeInfrastructure) { $infrastructureAmount = $parameters['asumsi_prasarana'] * $basicRetribution; $totalRetribution = $basicRetribution + $infrastructureAmount; } return [ 'success' => true, 'building_function_id' => $buildingFunctionId, 'floor_level' => $floorLevel, 'luas_bangunan' => $luasBangunan, 'indeks_lokalitas_type' => $indeksLokasi, 'calculation_breakdown' => [ 'rundown_4_calculation' => [ 'excel_formula' => '=ROUNDDOWN(($E13*($F13+$G13+(0.5*I$3))),4)', 'fungsi_bangunan' => $parameters['fungsi'], 'ip_permanen' => $parameters['ip_permanen'], 'ip_kompleksitas' => $parameters['ip_kompleksitas'], 'multiplier_ketinggian' => $parameters['multiplier_ketinggian'], 'ip_ketinggian' => $parameters['ip_ketinggian'], 'before_rounddown' => $parameters['fungsi'] * ($parameters['ip_permanen'] + $parameters['ip_kompleksitas'] + ($parameters['multiplier_ketinggian'] * $parameters['ip_ketinggian'])), 'after_rounddown' => $h5, 'precision' => 4 ], 'retribution_calculation' => [ 'basic_formula' => '1 * D5 * (N5 * 7035000 * H5 * 1)', 'infrastructure_formula' => 'O3 * basic_retribution', 'basic_amount' => $basicRetribution, 'infrastructure_amount' => $infrastructureAmount, 'total_amount' => $totalRetribution ] ], 'results' => [ 'h5_rundown4' => $h5, 'basic_retribution' => $basicRetribution, 'infrastructure_amount' => $infrastructureAmount, 'total_retribution' => $totalRetribution ] ]; } catch (\Exception $e) { return [ 'success' => false, 'error' => $e->getMessage(), 'building_function_id' => $buildingFunctionId, 'floor_level' => $floorLevel ]; } } /** * Calculate multiple floors retribution */ public function calculateMultiFloorRetribution($buildingFunctionId, array $floors, $luasBangunan, $indeksLokasi = 'sedang') { $floorDetails = []; $totalRetribution = 0; foreach ($floors as $floor) { $result = $this->calculateRetribution($buildingFunctionId, $floor, $luasBangunan, $indeksLokasi, true); if ($result['success']) { $floorDetails[$floor] = $result['results']; $totalRetribution += $result['results']['total_retribution']; } } return [ 'success' => true, 'building_function_id' => $buildingFunctionId, 'floors' => $floors, 'luas_bangunan' => $luasBangunan, 'indeks_lokalitas_type' => $indeksLokasi, 'floor_details' => $floorDetails, 'total_retribution' => $totalRetribution, 'average_per_floor' => count($floors) > 0 ? $totalRetribution / count($floors) : 0 ]; } /** * Calculate Rundown 4 per-floor value with ROUNDDOWN * Formula: =ROUNDDOWN(($E13*($F13+$G13+(0.5*I$3))),4) */ private function calculateRundown4($parameters) { $calculation = $parameters['fungsi'] * ($parameters['ip_permanen'] + $parameters['ip_kompleksitas'] + ($parameters['multiplier_ketinggian'] * $parameters['ip_ketinggian'])); // Apply ROUNDDOWN with 4 decimal places return floor($calculation * 10000) / 10000; } /** * Get parameter values for calculation */ private function getParameterValues($buildingFunctionId, $floorLevel, $indeksLokasi) { $buildingFunction = BuildingFunction::find($buildingFunctionId); if (!$buildingFunction) { throw new \Exception("Building function not found: {$buildingFunctionId}"); } $functionCode = strtolower($buildingFunction->code); $lokalitasMapping = [ 'rendah' => 'indeks_lokalitas_rendah', 'sedang' => 'indeks_lokalitas_sedang', 'tinggi' => 'indeks_lokalitas_tinggi' ]; $lokalitasParamCode = $lokalitasMapping[$indeksLokasi] ?? 'indeks_lokalitas_sedang'; $parameterCodes = [ 'tarif_dasar', 'koefisien_dasar', 'multiplier_ketinggian', 'asumsi_prasarana', $lokalitasParamCode, "ip_ketinggian_{$floorLevel}", "fungsi_{$functionCode}", "ip_permanen_{$functionCode}", "ip_kompleksitas_{$functionCode}" ]; $parameters = MasterParameter::whereIn('parameter_code', $parameterCodes)->get(); $values = []; foreach ($parameters as $param) { $values[$param->parameter_code] = $param->default_value; } return [ 'tarif_dasar' => $values['tarif_dasar'] ?? 7035000, 'koefisien_dasar' => $values['koefisien_dasar'] ?? 1, 'multiplier_ketinggian' => $values['multiplier_ketinggian'] ?? 0.5, 'asumsi_prasarana' => $values['asumsi_prasarana'] ?? 0.5, 'indeks_lokalitas' => $values[$lokalitasParamCode] ?? 0.004, 'ip_ketinggian' => $values["ip_ketinggian_{$floorLevel}"] ?? 1.0, 'fungsi' => $values["fungsi_{$functionCode}"] ?? 0, 'ip_permanen' => $values["ip_permanen_{$functionCode}"] ?? 0, 'ip_kompleksitas' => $values["ip_kompleksitas_{$functionCode}"] ?? 0 ]; } }