diff --git a/.config/psysh/psysh_history b/.config/psysh/psysh_history index 441f57d..fbad47c 100644 --- a/.config/psysh/psysh_history +++ b/.config/psysh/psysh_history @@ -17,3 +17,8 @@ exit Bigdataresume::generateResumeData(253,2025,'simbg'); BigdataResume::generateResumeData(253,2025,'simbg'); exit +BigdataResume::generateResumeData(253,2025,"simbg"); +BigdataResume::generateResumeData(253,2025,"simbg"); +exit +BigdataResume::generateResumeData(253,2025,"simbg"); +exit diff --git a/.npm/_logs/2025-08-19T10_49_06_806Z-debug-0.log b/.npm/_logs/2025-08-19T10_49_06_806Z-debug-0.log new file mode 100644 index 0000000..b9eaa70 --- /dev/null +++ b/.npm/_logs/2025-08-19T10_49_06_806Z-debug-0.log @@ -0,0 +1,17 @@ +0 verbose cli /usr/bin/node /usr/bin/npm +1 info using npm@10.8.2 +2 info using node@v18.20.8 +3 silly config load:file:/usr/lib/node_modules/npm/npmrc +4 silly config load:file:/var/www/.npmrc +5 silly config load:file:/usr/etc/npmrc +6 verbose title npm run build +7 verbose argv "run" "build" +8 verbose logfile logs-max:10 dir:/var/www/.npm/_logs/2025-08-19T10_49_06_806Z- +9 verbose logfile /var/www/.npm/_logs/2025-08-19T10_49_06_806Z-debug-0.log +10 silly logfile done cleaning log files +11 verbose cwd /var/www +12 verbose os Linux 6.6.87.2-microsoft-standard-WSL2 +13 verbose node v18.20.8 +14 verbose npm v10.8.2 +15 verbose exit 0 +16 info ok diff --git a/app/Enums/PbgTaskFilterData.php b/app/Enums/PbgTaskFilterData.php index bd87391..0f80bcc 100644 --- a/app/Enums/PbgTaskFilterData.php +++ b/app/Enums/PbgTaskFilterData.php @@ -13,6 +13,11 @@ enum PbgTaskFilterData : string case issuance_realization_pbg = 'issuance-realization-pbg'; case process_in_technical_office = 'process-in-technical-office'; case waiting_click_dpmptsp = 'waiting-click-dpmptsp'; + case non_business_rab = 'non-business-rab'; + case non_business_krk = 'non-business-krk'; + case business_rab = 'business-rab'; + case business_krk = 'business-krk'; + case business_dlh = 'business-dlh'; public static function getAllOptions() : array { return [ @@ -25,6 +30,11 @@ enum PbgTaskFilterData : string self::issuance_realization_pbg->value => 'Realisasi PBG', self::process_in_technical_office->value => 'Proses Di Dinas Teknis', self::waiting_click_dpmptsp->value => 'Menunggu Klik DPMPTSP', + self::non_business_rab->value => 'Non Usaha - RAB', + self::non_business_krk->value => 'Non Usaha - KRK', + self::business_rab->value => 'Usaha - RAB', + self::business_krk->value => 'Usaha - KRK', + self::business_dlh->value => 'Usaha - DLH', ]; } } diff --git a/app/Http/Controllers/Api/BigDataResumeController.php b/app/Http/Controllers/Api/BigDataResumeController.php index 79a91f6..3952c34 100644 --- a/app/Http/Controllers/Api/BigDataResumeController.php +++ b/app/Http/Controllers/Api/BigDataResumeController.php @@ -8,6 +8,7 @@ use App\Http\Controllers\Controller; use App\Http\Resources\BigdataResumeResource; use App\Models\BigdataResume; use App\Models\DataSetting; +use App\Models\SpatialPlanning; use Barryvdh\DomPDF\Facade\Pdf; use Carbon\Carbon; use Illuminate\Http\Request; @@ -26,13 +27,12 @@ class BigDataResumeController extends Controller $type = $request->get("type"); if (!$filterDate || $filterDate === "latest") { - $big_data_resume = BigdataResume::where('resume_type', $type)->latest()->first(); + $big_data_resume = BigdataResume::latest()->first(); if (!$big_data_resume) { return $this->response_empty_resume(); } } else { - $big_data_resume = BigdataResume::where('resume_type', $type) - ->whereDate('created_at', $filterDate) + $big_data_resume = BigdataResume::whereDate('created_at', $filterDate) ->orderBy('id', 'desc') ->first(); @@ -54,7 +54,11 @@ class BigDataResumeController extends Controller $proses_dinas_teknis_sum = $big_data_resume->process_in_technical_office_sum; $proses_dinas_teknis_count = $big_data_resume->process_in_technical_office_count; - $tata_ruang = $big_data_resume->spatial_sum; + // Get real-time spatial planning data using new calculation formula + $spatialData = $this->getSpatialPlanningData(); + $tata_ruang = $spatialData['sum']; + $tata_ruang_count = $spatialData['count']; + $kekurangan_potensi = $target_pad - $big_data_resume->potention_sum; // percentage kekurangan potensi @@ -115,8 +119,8 @@ class BigDataResumeController extends Controller 'percentage' => 100, ], 'tata_ruang' => [ - 'sum' => $big_data_resume->spatial_sum, - 'count' => $big_data_resume->spatial_count, + 'sum' => $tata_ruang, + 'count' => $tata_ruang_count, 'percentage' => $tata_ruang_percentage, ], 'kekurangan_potensi' => [ @@ -399,4 +403,58 @@ class BigDataResumeController extends Controller return response()->json($result); } + + /** + * Get spatial planning data using new calculation formula + */ + private function getSpatialPlanningData(): array + { + try { + // Get spatial plannings that are not yet issued (is_terbit = false) and have valid data + $spatialPlannings = SpatialPlanning::where('land_area', '>', 0) + ->where('site_bcr', '>', 0) + ->where('is_terbit', false) + ->get(); + + $totalSum = 0; + $businessCount = 0; + $nonBusinessCount = 0; + + foreach ($spatialPlannings as $spatialPlanning) { + // Use new calculation formula: LUAS LAHAN × BCR × HARGA SATUAN + $calculatedAmount = $spatialPlanning->calculated_retribution; + $totalSum += $calculatedAmount; + + // Count business types + if ($spatialPlanning->is_business_type) { + $businessCount++; + } else { + $nonBusinessCount++; + } + } + + Log::info("Real-time Spatial Planning Data (is_terbit = false only)", [ + 'total_records' => $spatialPlannings->count(), + 'business_count' => $businessCount, + 'non_business_count' => $nonBusinessCount, + 'total_sum' => $totalSum, + 'filtered_by' => 'is_terbit = false' + ]); + + return [ + 'count' => $spatialPlannings->count(), + 'sum' => (float) $totalSum, + 'business_count' => $businessCount, + 'non_business_count' => $nonBusinessCount, + ]; + } catch (\Exception $e) { + Log::error("Error getting spatial planning data", ['error' => $e->getMessage()]); + return [ + 'count' => 0, + 'sum' => 0.0, + 'business_count' => 0, + 'non_business_count' => 0, + ]; + } + } } diff --git a/app/Http/Controllers/Api/RequestAssignmentController.php b/app/Http/Controllers/Api/RequestAssignmentController.php index 61ed865..e85f961 100644 --- a/app/Http/Controllers/Api/RequestAssignmentController.php +++ b/app/Http/Controllers/Api/RequestAssignmentController.php @@ -25,7 +25,7 @@ class RequestAssignmentController extends Controller // Build base query for counting (without relationships to avoid duplicates) $baseQuery = PbgTask::query(); - // Filter only valid data (is_valid = true) + // Always filter only valid data (is_valid = true) $baseQuery->where('is_valid', true); // Apply year filter if provided (to match BigdataResume behavior) @@ -35,100 +35,17 @@ class RequestAssignmentController extends Controller Log::info('RequestAssignmentController year filter applied', ['year' => $year]); } - // Apply filters to base query (matching BigdataResume logic exactly) - if ($request->has('filter') && !empty($request->get('filter'))) { - $filter = strtolower(trim($request->get('filter'))); - - // Log filter for debugging - Log::info('RequestAssignmentController filter applied', ['filter' => $filter, 'original' => $request->get('filter')]); - - switch ($filter) { - case 'non-business': - // Match BigdataResume non-business logic exactly - $baseQuery->where(function ($q) { - $q->where(function ($q2) { - $q2->where(function ($q3) { - $q3->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%fungsi usaha%']) - ->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%sebagai tempat usaha%']); - }) - ->orWhereNull('function_type'); - }) - ->whereIn("status", PbgTaskStatus::getNonVerified()); - }); - break; - - case 'business': - // Match BigdataResume business logic exactly - $baseQuery->where(function ($q) { - $q->where(function ($q2) { - $q2->whereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%fungsi usaha%']) - ->orWhereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%sebagai tempat usaha%']); - }) - ->whereIn("status", PbgTaskStatus::getNonVerified()); - }); - break; - - case 'verified': - // Match BigdataResume verified logic exactly - $baseQuery->whereIn("status", PbgTaskStatus::getVerified()); - break; - - case 'non-verified': - // Match BigdataResume non-verified logic exactly - $baseQuery->whereIn("status", PbgTaskStatus::getNonVerified()); - break; - - case 'potention': - // Match BigdataResume potention logic exactly - $baseQuery->whereIn("status", PbgTaskStatus::getPotention()); - break; - - case 'issuance-realization-pbg': - // Match BigdataResume issuance realization logic exactly - $baseQuery->whereIn("status", PbgTaskStatus::getIssuanceRealizationPbg()); - break; - - case 'process-in-technical-office': - // Match BigdataResume process in technical office logic exactly - $baseQuery->whereIn("status", PbgTaskStatus::getProcessInTechnicalOffice()); - break; - - case 'waiting-click-dpmptsp': - // Match BigdataResume waiting click DPMPTSP logic exactly - $baseQuery->whereIn("status", PbgTaskStatus::getWaitingClickDpmptsp()); - break; - - default: - // Log unrecognized filter for debugging - Log::warning('Unrecognized filter value', ['filter' => $filter, 'original' => $request->get('filter')]); - break; - } - } - - // Apply search to base query - if ($request->has('search') && !empty($request->get("search"))) { - $search = $request->get('search'); - - // Search in pbg_task columns - $baseQuery->where(function ($q) use ($search) { - $q->where('name', 'LIKE', "%$search%") - ->orWhere('registration_number', 'LIKE', "%$search%") - ->orWhere('owner_name', 'LIKE', "%$search%") - ->orWhere('address', 'LIKE', "%$search%"); - }); - - // If search term exists, also find UUIDs from name_building search - $namesBuildingUuids = DB::table('pbg_task_details') - ->where('name_building', 'LIKE', "%$search%") - ->pluck('pbg_task_uid') - ->toArray(); - - // If we found matching name_building records, include them in the search - if (!empty($namesBuildingUuids)) { - $baseQuery->orWhereIn('uuid', $namesBuildingUuids); - } - } + // Get filter value, default to 'all' if not provided or empty + $filter = $request->has('filter') && !empty($request->get('filter')) + ? strtolower(trim($request->get('filter'))) + : 'all'; + + // Log filter for debugging + Log::info('RequestAssignmentController filter applied', ['filter' => $filter, 'original' => $request->get('filter')]); + // Apply filters to base query using single consolidated method + $this->applyFilter($baseQuery, $filter); + // Get accurate count from base query (without relationships) $accurateCount = $baseQuery->count(); @@ -144,7 +61,7 @@ class RequestAssignmentController extends Controller // Log final query count for debugging Log::info('RequestAssignmentController final result', [ - 'filter' => $request->get('filter'), + 'filter' => $filter, 'search' => $request->get('search'), 'year' => $request->get('year'), 'accurate_count' => $accurateCount, @@ -153,13 +70,17 @@ class RequestAssignmentController extends Controller ]); // Cross-validation with BigdataResume logic (for debugging consistency) - if ($request->has('filter') && $request->has('year') && - !empty($request->get('filter')) && !empty($request->get('year'))) { - $this->validateConsistencyWithBigdataResume($request->get('filter'), $request->get('year'), $accurateCount); + if ($filter !== 'all' && $request->has('year') && !empty($request->get('year'))) { + $this->validateConsistencyWithBigdataResume($filter, $request->get('year'), $accurateCount); + } + + // Apply search to data query + if ($request->has('search') && !empty($request->get("search"))) { + $this->applySearch($dataQuery, $request->get('search')); } // Additional logging for potention filter - if ($request->get('filter') === 'potention') { + if ($filter === 'potention') { $rejectedCount = PbgTask::whereIn('status', PbgTaskStatus::getRejected())->count(); Log::info('Potention filter details', [ 'potention_count' => $accurateCount, @@ -170,8 +91,8 @@ class RequestAssignmentController extends Controller } // Also log to console for immediate debugging - if ($request->has('filter') && !empty($request->get('filter'))) { - error_log('RequestAssignment Filter Debug: ' . $request->get('filter') . ' -> Count: ' . $accurateCount); + if ($filter !== 'all') { + error_log('RequestAssignment Filter Debug: ' . $filter . ' -> Count: ' . $accurateCount); } // Get paginated results with relationships @@ -183,6 +104,198 @@ class RequestAssignmentController extends Controller return RequestAssignmentResouce::collection($paginatedResults); } + /** + * Apply filter logic to the query + */ + private function applyFilter($query, string $filter) + { + switch ($filter) { + case 'all': + // No additional filters, just return all valid records + break; + case 'non-business': + // Match BigdataResume non-business logic exactly + $query->where(function ($q) { + $q->where(function ($q2) { + $q2->where(function ($q3) { + $q3->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%fungsi usaha%']) + ->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%sebagai tempat usaha%']); + }) + ->orWhereNull('function_type'); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }); + break; + + case 'business': + // Match BigdataResume business logic exactly + $query->where(function ($q) { + $q->where(function ($q2) { + $q2->whereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%fungsi usaha%']) + ->orWhereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%sebagai tempat usaha%']); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }); + break; + + case 'verified': + // Match BigdataResume verified logic exactly + $query->whereIn("status", PbgTaskStatus::getVerified()); + break; + + case 'non-verified': + // Match BigdataResume non-verified logic exactly + $query->whereIn("status", PbgTaskStatus::getNonVerified()); + break; + + case 'potention': + // Match BigdataResume potention logic exactly + $query->whereIn("status", PbgTaskStatus::getPotention()); + break; + + case 'issuance-realization-pbg': + // Match BigdataResume issuance realization logic exactly + $query->whereIn("status", PbgTaskStatus::getIssuanceRealizationPbg()); + break; + + case 'process-in-technical-office': + // Match BigdataResume process in technical office logic exactly + $query->whereIn("status", PbgTaskStatus::getProcessInTechnicalOffice()); + break; + + case 'waiting-click-dpmptsp': + // Match BigdataResume waiting click DPMPTSP logic exactly + $query->whereIn("status", PbgTaskStatus::getWaitingClickDpmptsp()); + break; + + case 'non-business-rab': + // Non-business tasks that have RAB documents (data_type = 3) with at least one status != 1 + $query->where(function ($q) { + $q->where(function ($q2) { + $q2->where(function ($q3) { + $q3->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%fungsi usaha%']) + ->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%sebagai tempat usaha%']); + }) + ->orWhereNull('function_type'); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }) + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('pbg_task_detail_data_lists') + ->whereColumn('pbg_task_detail_data_lists.pbg_task_uuid', 'pbg_task.uuid') + ->where('pbg_task_detail_data_lists.data_type', 3) + ->where('pbg_task_detail_data_lists.status', '!=', 1); + }); + break; + + case 'non-business-krk': + // Non-business tasks that have KRK documents (data_type = 2) with at least one status != 1 + $query->where(function ($q) { + $q->where(function ($q2) { + $q2->where(function ($q3) { + $q3->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%fungsi usaha%']) + ->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%sebagai tempat usaha%']); + }) + ->orWhereNull('function_type'); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }) + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('pbg_task_detail_data_lists') + ->whereColumn('pbg_task_detail_data_lists.pbg_task_uuid', 'pbg_task.uuid') + ->where('pbg_task_detail_data_lists.data_type', 2) + ->where('pbg_task_detail_data_lists.status', '!=', 1); + }); + break; + + case 'business-rab': + // Business tasks that have RAB documents (data_type = 3) with at least one status != 1 + $query->where(function ($q) { + $q->where(function ($q2) { + $q2->whereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%fungsi usaha%']) + ->orWhereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%sebagai tempat usaha%']); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }) + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('pbg_task_detail_data_lists') + ->whereColumn('pbg_task_detail_data_lists.pbg_task_uuid', 'pbg_task.uuid') + ->where('pbg_task_detail_data_lists.data_type', 3) + ->where('pbg_task_detail_data_lists.status', '!=', 1); + }); + break; + + case 'business-krk': + // Business tasks that have KRK documents (data_type = 2) with at least one status != 1 + $query->where(function ($q) { + $q->where(function ($q2) { + $q2->whereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%fungsi usaha%']) + ->orWhereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%sebagai tempat usaha%']); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }) + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('pbg_task_detail_data_lists') + ->whereColumn('pbg_task_detail_data_lists.pbg_task_uuid', 'pbg_task.uuid') + ->where('pbg_task_detail_data_lists.data_type', 2) + ->where('pbg_task_detail_data_lists.status', '!=', 1); + }); + break; + + case 'business-dlh': + // Business tasks that have DLH documents (data_type = 5) with at least one status != 1 + $query->where(function ($q) { + $q->where(function ($q2) { + $q2->whereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%fungsi usaha%']) + ->orWhereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%sebagai tempat usaha%']); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }) + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('pbg_task_detail_data_lists') + ->whereColumn('pbg_task_detail_data_lists.pbg_task_uuid', 'pbg_task.uuid') + ->where('pbg_task_detail_data_lists.data_type', 5) + ->where('pbg_task_detail_data_lists.status', '!=', 1); + }); + break; + + default: + // Log unrecognized filter for debugging + Log::warning('Unrecognized filter value', ['filter' => $filter]); + break; + } + } + + /** + * Apply search logic to the query + */ + private function applySearch($query, string $search) + { + // Search in pbg_task columns + $query->where(function ($q) use ($search) { + $q->where('name', 'LIKE', "%$search%") + ->orWhere('registration_number', 'LIKE', "%$search%") + ->orWhere('owner_name', 'LIKE', "%$search%") + ->orWhere('address', 'LIKE', "%$search%"); + }); + + // If search term exists, also find UUIDs from name_building search + $namesBuildingUuids = DB::table('pbg_task_details') + ->where('name_building', 'LIKE', "%$search%") + ->pluck('pbg_task_uid') + ->toArray(); + + // If we found matching name_building records, include them in the search + if (!empty($namesBuildingUuids)) { + $query->orWhereIn('uuid', $namesBuildingUuids); + } + } + public function report_payment_recaps(Request $request) { try { @@ -369,6 +482,112 @@ class RequestAssignmentController extends Controller ->whereYear('task_created_at', $year) ->count(); break; + + case 'non-business-rab': + $bigdataResumeCount = PbgTask::where(function ($q) { + $q->where(function ($q2) { + $q2->where(function ($q3) { + $q3->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%fungsi usaha%']) + ->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%sebagai tempat usaha%']); + }) + ->orWhereNull('function_type'); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }) + ->where('is_valid', true) + ->whereYear('task_created_at', $year) + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('pbg_task_detail_data_lists') + ->whereColumn('pbg_task_detail_data_lists.pbg_task_uuid', 'pbg_task.uuid') + ->where('pbg_task_detail_data_lists.data_type', 3) + ->where('pbg_task_detail_data_lists.status', '!=', 1); + }) + ->count(); + break; + + case 'non-business-krk': + $bigdataResumeCount = PbgTask::where(function ($q) { + $q->where(function ($q2) { + $q2->where(function ($q3) { + $q3->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%fungsi usaha%']) + ->whereRaw("LOWER(TRIM(function_type)) NOT LIKE ?", ['%sebagai tempat usaha%']); + }) + ->orWhereNull('function_type'); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }) + ->where('is_valid', true) + ->whereYear('task_created_at', $year) + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('pbg_task_detail_data_lists') + ->whereColumn('pbg_task_detail_data_lists.pbg_task_uuid', 'pbg_task.uuid') + ->where('pbg_task_detail_data_lists.data_type', 2) + ->where('pbg_task_detail_data_lists.status', '!=', 1); + }) + ->count(); + break; + + case 'business-rab': + $bigdataResumeCount = PbgTask::where(function ($q) { + $q->where(function ($q2) { + $q2->whereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%fungsi usaha%']) + ->orWhereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%sebagai tempat usaha%']); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }) + ->where('is_valid', true) + ->whereYear('task_created_at', $year) + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('pbg_task_detail_data_lists') + ->whereColumn('pbg_task_detail_data_lists.pbg_task_uuid', 'pbg_task.uuid') + ->where('pbg_task_detail_data_lists.data_type', 3) + ->where('pbg_task_detail_data_lists.status', '!=', 1); + }) + ->count(); + break; + + case 'business-krk': + $bigdataResumeCount = PbgTask::where(function ($q) { + $q->where(function ($q2) { + $q2->whereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%fungsi usaha%']) + ->orWhereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%sebagai tempat usaha%']); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }) + ->where('is_valid', true) + ->whereYear('task_created_at', $year) + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('pbg_task_detail_data_lists') + ->whereColumn('pbg_task_detail_data_lists.pbg_task_uuid', 'pbg_task.uuid') + ->where('pbg_task_detail_data_lists.data_type', 2) + ->where('pbg_task_detail_data_lists.status', '!=', 1); + }) + ->count(); + break; + + case 'business-dlh': + $bigdataResumeCount = PbgTask::where(function ($q) { + $q->where(function ($q2) { + $q2->whereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%fungsi usaha%']) + ->orWhereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%sebagai tempat usaha%']); + }) + ->whereIn("status", PbgTaskStatus::getNonVerified()); + }) + ->where('is_valid', true) + ->whereYear('task_created_at', $year) + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('pbg_task_detail_data_lists') + ->whereColumn('pbg_task_detail_data_lists.pbg_task_uuid', 'pbg_task.uuid') + ->where('pbg_task_detail_data_lists.data_type', 5) + ->where('pbg_task_detail_data_lists.status', '!=', 1); + }) + ->count(); + break; default: Log::info('Unknown filter for consistency validation', [ diff --git a/app/Http/Controllers/Api/SpatialPlanningController.php b/app/Http/Controllers/Api/SpatialPlanningController.php index 7635ab7..11a256a 100644 --- a/app/Http/Controllers/Api/SpatialPlanningController.php +++ b/app/Http/Controllers/Api/SpatialPlanningController.php @@ -26,6 +26,10 @@ class SpatialPlanningController extends Controller $search = $request->input('search', ''); $query = SpatialPlanning::query(); + + // Only include spatial plannings that are not yet issued (is_terbit = false) + $query->where('is_terbit', false); + if ($search) { $query->where(function ($q) use ($search) { $q->where('name', 'like', "%$search%") @@ -42,9 +46,11 @@ class SpatialPlanningController extends Controller // Menambhakan nomor urut (No) $start = ($spatialPlannings->currentPage()-1) * $perPage + 1; - // Tambahkan nomor urut ke dalam data + // Tambahkan nomor urut ke dalam data (calculated_retribution sudah auto-append) $data = $spatialPlannings->map(function ($item, $index) use ($start) { - return array_merge($item->toArray(), ['no' => $start + $index]); + $itemArray = $item->toArray(); + $itemArray['no'] = $start + $index; + return $itemArray; }); info($data); @@ -104,9 +110,10 @@ class SpatialPlanningController extends Controller /** * Display the specified resource. */ - public function show(SpatialPlanning $spatialPlanning): SpatialPlanning + public function show(SpatialPlanning $spatialPlanning): array { - return $spatialPlanning; + // calculated_retribution and formatted_retribution are already appended via $appends + return $spatialPlanning->toArray(); } /** diff --git a/app/Http/Controllers/Data/SpatialPlanningController.php b/app/Http/Controllers/Data/SpatialPlanningController.php index 8f62ac4..7f1bffb 100644 --- a/app/Http/Controllers/Data/SpatialPlanningController.php +++ b/app/Http/Controllers/Data/SpatialPlanningController.php @@ -82,9 +82,15 @@ class SpatialPlanningController extends Controller "kbli"=> "KBLI", "activities"=> "Kegiatan", "area"=> "Luas (m2)", + "land_area"=> "Luas Lahan (m2)", "location"=> "Lokasi", "number"=> "Nomor", "date"=> "Tanggal", + "site_bcr"=> "BCR", + "building_function"=> "Fungsi Bangunan", + "business_type_info"=> "Jenis Usaha", + "is_terbit"=> "Status Terbit", + "calculated_retribution"=> "Retribusi", ]; } @@ -95,9 +101,15 @@ class SpatialPlanningController extends Controller "kbli"=> "text", "activities"=> "text", "area"=> "text", + "land_area"=> "text", "location"=> "text", "number"=> "text", "date"=> "date", + "site_bcr"=> "text", + "building_function"=> "text", + "business_type_info"=> "readonly", + "is_terbit"=> "select", + "calculated_retribution"=> "readonly", ]; } } diff --git a/app/Http/Requests/SpatialPlanningRequest.php b/app/Http/Requests/SpatialPlanningRequest.php index 853d646..9714131 100644 --- a/app/Http/Requests/SpatialPlanningRequest.php +++ b/app/Http/Requests/SpatialPlanningRequest.php @@ -22,13 +22,14 @@ class SpatialPlanningRequest extends FormRequest public function rules(): array { return [ - 'name' => 'string', - 'kbli' => 'string', - 'activities' => 'string', - 'area' => 'string', - 'location' => 'string', - 'number' => 'string', - 'date' => 'date_format:Y-m-d', + 'name' => 'nullable|string', + 'kbli' => 'nullable|string', + 'activities' => 'nullable|string', + 'area' => 'nullable|string', + 'location' => 'nullable|string', + 'number' => 'nullable|string', + 'date' => 'nullable|date_format:Y-m-d', + 'is_terbit' => 'nullable|boolean', ]; } diff --git a/app/Http/Requests/SpatialPlanningsRequest.php b/app/Http/Requests/SpatialPlanningsRequest.php deleted file mode 100644 index 73971b4..0000000 --- a/app/Http/Requests/SpatialPlanningsRequest.php +++ /dev/null @@ -1,35 +0,0 @@ -|string> - */ - public function rules(): array - { - return [ - 'name' => ['required','string','max:255'], - 'kbli' => ['required','string','max:255'], - 'kegiatan' => ['required','string'], - 'luas' => ['required','numeric','regex:/^\d{1,16}(\.\d{1,2})?$/'], - 'lokasi' => ['required','string'], - 'nomor' => ['required','string','max:255',Rule::unique('spatial_plannings')->ignore($this->id)], - 'sp_date' => ['required','date'], - ]; - } -} diff --git a/app/Http/Resources/SpatialPlanningsResource.php b/app/Http/Resources/SpatialPlanningsResource.php deleted file mode 100644 index 40a29d9..0000000 --- a/app/Http/Resources/SpatialPlanningsResource.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ - public function toArray(Request $request): array - { - return parent::toArray($request); - } -} diff --git a/app/Models/BigdataResume.php b/app/Models/BigdataResume.php index d33dfcd..26b8428 100644 --- a/app/Models/BigdataResume.php +++ b/app/Models/BigdataResume.php @@ -166,16 +166,13 @@ class BigdataResume extends Model ') ->value('total_count') ?? 0; - // Non-Business DLH count - for each non-business task with data_type=5: + // Business DLH count - for each business task with data_type=5: // if any status != 1 then return 1, if all status = 1 then return 0, then sum all $business_dlh_count = DB::table('pbg_task') ->where(function ($q) { $q->where(function ($q2) { - $q2->where(function ($q3) { - $q3->whereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%fungsi usaha%']) - ->whereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%sebagai tempat usaha%']); - }) - ->orWhereNull('function_type'); + $q2->whereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%fungsi usaha%']) + ->orWhereRaw("LOWER(TRIM(function_type)) LIKE ?", ['%sebagai tempat usaha%']); }) ->whereIn("status", PbgTaskStatus::getNonVerified()); }) diff --git a/app/Models/SpatialPlanning.php b/app/Models/SpatialPlanning.php index 7e8fda9..237c31e 100644 --- a/app/Models/SpatialPlanning.php +++ b/app/Models/SpatialPlanning.php @@ -34,14 +34,24 @@ class SpatialPlanning extends Model * * @var array */ - protected $fillable = ['name', 'kbli', 'activities', 'area', 'location', 'number', 'date', 'no_tapak', 'no_skkl', 'no_ukl', 'building_function', 'sub_building_function', 'number_of_floors', 'land_area', 'site_bcr']; + protected $fillable = ['name', 'kbli', 'activities', 'area', 'location', 'number', 'date', 'no_tapak', 'no_skkl', 'no_ukl', 'building_function', 'sub_building_function', 'number_of_floors', 'land_area', 'site_bcr', 'is_terbit']; protected $casts = [ 'area' => 'decimal:6', 'land_area' => 'decimal:6', 'site_bcr' => 'decimal:6', 'number_of_floors' => 'integer', - 'date' => 'date' + 'date' => 'date', + 'is_terbit' => 'boolean' + ]; + + protected $appends = [ + 'calculated_retribution', + 'formatted_retribution', + 'is_business_type', + 'calculation_details', + 'old_calculation_amount', + 'calculation_source' ]; @@ -62,7 +72,171 @@ class SpatialPlanning extends Model return (float) ($this->area ?? $this->land_area ?? 0); } + /** + * Get calculated retribution amount + * Priority: Manual calculation (new formula) > Active calculation (old system) + */ + public function getCalculatedRetributionAttribute(): float + { + try { + // PRIORITY 1: Use new manual formula (LUAS LAHAN × BCR × HARGA SATUAN) + $manualCalculation = $this->calculateRetributionManually(); + + // If manual calculation is valid (> 0), use it + if ($manualCalculation > 0) { + return $manualCalculation; + } + + // PRIORITY 2: Fallback to active retribution calculation if exists + $activeCalculation = $this->activeRetributionCalculation; + + if ($activeCalculation && $activeCalculation->retributionCalculation) { + return (float) $activeCalculation->retributionCalculation->retribution_amount; + } + + // PRIORITY 3: Return 0 if nothing works + return 0.0; + + } catch (\Exception $e) { + \Log::warning('Failed to calculate retribution for SpatialPlanning ID: ' . $this->id, [ + 'error' => $e->getMessage(), + 'spatial_planning' => $this->toArray() + ]); + return 0.0; + } + } + /** + * Manual calculation based on area and building function + * Formula: LUAS LAHAN × BCR × HARGA SATUAN + * NON USAHA: 16,000 per m2 + * USAHA: 44,300 per m2 + */ + private function calculateRetributionManually(): float + { + // Get land area (luas lahan) + $landArea = (float) ($this->land_area ?? 0); + + // Get BCR (Building Coverage Ratio) - convert from percentage to decimal + $bcrPercentage = (float) ($this->site_bcr ?? 0); + $bcr = $bcrPercentage / 100; // Convert percentage to decimal (24.49% -> 0.2449) + + if ($landArea <= 0 || $bcr <= 0) { + return 0.0; + } + + // Determine if this is business (USAHA) or non-business (NON USAHA) + $isBusiness = $this->isBusinessType(); + + // Set unit price based on business type + $unitPrice = $isBusiness ? 44300 : 16000; + + // Calculate: LUAS LAHAN × BCR (as decimal) × HARGA SATUAN + $calculatedAmount = $landArea * $bcr * $unitPrice; + + return $calculatedAmount; + } + /** + * Determine if this spatial planning is for business purposes + */ + private function isBusinessType(): bool + { + $buildingFunction = strtolower($this->building_function ?? $this->activities ?? ''); + + // Business keywords + $businessKeywords = [ + 'usaha', 'dagang', 'perdagangan', 'komersial', 'commercial', 'bisnis', 'business', + 'toko', 'warung', 'pasar', 'kios', 'mall', 'plaza', 'supermarket', 'department', + 'hotel', 'resort', 'restoran', 'restaurant', 'cafe', 'kantor', 'perkantoran', 'office', + 'industri', 'pabrik', 'gudang', 'warehouse', 'manufacturing', 'produksi', + 'bengkel', 'workshop', 'showroom', 'dealer', 'apotek', 'pharmacy', 'klinik swasta', + 'rumah sakit swasta', 'bank', 'atm', 'money changer', 'asuransi', 'leasing', + 'rental', 'sewa', 'jasa', 'service', 'salon', 'spa', 'fitness', 'gym', + 'tempat usaha', 'fungsi usaha', 'kegiatan usaha', 'bangunan usaha' + ]; + + // Check if any business keyword is found + foreach ($businessKeywords as $keyword) { + if (str_contains($buildingFunction, $keyword)) { + return true; + } + } + + // Non-business (default) + return false; + } + /** + * Get formatted retribution amount for display + */ + public function getFormattedRetributionAttribute(): string + { + $amount = $this->calculated_retribution; + return number_format($amount, 0, ',', '.'); + } + + /** + * Check if this is business type + */ + public function getIsBusinessTypeAttribute(): bool + { + return $this->isBusinessType(); + } + + /** + * Get calculation details for transparency + */ + public function getCalculationDetailsAttribute(): array + { + $landArea = (float) ($this->land_area ?? 0); + $bcrPercentage = (float) ($this->site_bcr ?? 0); + $bcr = $bcrPercentage / 100; // Convert to decimal + $isBusiness = $this->isBusinessType(); + $unitPrice = $isBusiness ? 44300 : 16000; + $calculatedAmount = $landArea * $bcr * $unitPrice; + + return [ + 'formula' => 'LUAS LAHAN × BCR (decimal) × HARGA SATUAN', + 'land_area' => $landArea, + 'bcr_percentage' => $bcrPercentage, + 'bcr_decimal' => $bcr, + 'business_type' => $isBusiness ? 'USAHA' : 'NON USAHA', + 'unit_price' => $unitPrice, + 'calculation' => "{$landArea} × {$bcr} × {$unitPrice}", + 'result' => $calculatedAmount, + 'building_function' => $this->building_function ?? $this->activities ?? 'N/A' + ]; + } + + /** + * Get old calculation amount from database + */ + public function getOldCalculationAmountAttribute(): float + { + $activeCalculation = $this->activeRetributionCalculation; + + if ($activeCalculation && $activeCalculation->retributionCalculation) { + return (float) $activeCalculation->retributionCalculation->retribution_amount; + } + + return 0.0; + } + + /** + * Get calculation source info + */ + public function getCalculationSourceAttribute(): string + { + $manualCalculation = $this->calculateRetributionManually(); + $hasActiveCalculation = $this->hasActiveRetributionCalculation(); + + if ($manualCalculation > 0) { + return $hasActiveCalculation ? 'NEW_FORMULA' : 'NEW_FORMULA_ONLY'; + } elseif ($hasActiveCalculation) { + return 'OLD_DATABASE'; + } + + return 'NONE'; + } } diff --git a/app/Services/ServiceGoogleSheet.php b/app/Services/ServiceGoogleSheet.php index 81e9c0a..b10d197 100644 --- a/app/Services/ServiceGoogleSheet.php +++ b/app/Services/ServiceGoogleSheet.php @@ -539,14 +539,16 @@ class ServiceGoogleSheet } /** - * Get count of spatial plannings that have active retribution calculations + * Get count of spatial plannings that can be calculated with new formula */ public function getSpatialPlanningWithCalculationCount(): int { try { - return SpatialPlanning::whereHas('retributionCalculations', function ($query) { - $query->where('is_active', true); - })->count(); + // Count spatial plannings that have valid data and are not yet issued (is_terbit = false) + return SpatialPlanning::where('land_area', '>', 0) + ->where('site_bcr', '>', 0) + ->where('is_terbit', false) + ->count(); } catch (\Exception $e) { Log::error("Error getting spatial planning with calculation count", ['error' => $e->getMessage()]); return 0; @@ -554,25 +556,29 @@ class ServiceGoogleSheet } /** - * Get total sum of retribution amounts for spatial plannings with active calculations + * Get total sum of retribution amounts using new calculation formula */ public function getSpatialPlanningCalculationSum(): float { try { - // Get all spatial plannings that have active calculations - $spatialPlannings = SpatialPlanning::whereHas('retributionCalculations', function ($query) { - $query->where('is_active', true); - })->with(['retributionCalculations.retributionCalculation']) - ->get(); + // Get spatial plannings that are not yet issued (is_terbit = false) and have valid data + $spatialPlannings = SpatialPlanning::where('land_area', '>', 0) + ->where('site_bcr', '>', 0) + ->where('is_terbit', false) + ->get(); $totalSum = 0; foreach ($spatialPlannings as $spatialPlanning) { - $activeCalculation = $spatialPlanning->activeRetributionCalculation; - if ($activeCalculation && $activeCalculation->retributionCalculation) { - $totalSum += $activeCalculation->retributionCalculation->retribution_amount; - } + // Use new calculation formula: LUAS LAHAN × BCR × HARGA SATUAN + $totalSum += $spatialPlanning->calculated_retribution; } + Log::info("Spatial Planning Calculation Sum (is_terbit = false only)", [ + 'total_records' => $spatialPlannings->count(), + 'total_sum' => $totalSum, + 'filtered_by' => 'is_terbit = false' + ]); + return (float) $totalSum; } catch (\Exception $e) { Log::error("Error getting spatial planning calculation sum", ['error' => $e->getMessage()]); diff --git a/database/migrations/2025_08_19_145855_add_is_terbit_in_spatial_plannings_table.php b/database/migrations/2025_08_19_145855_add_is_terbit_in_spatial_plannings_table.php new file mode 100644 index 0000000..2dc1bcc --- /dev/null +++ b/database/migrations/2025_08_19_145855_add_is_terbit_in_spatial_plannings_table.php @@ -0,0 +1,28 @@ +boolean('is_terbit')->default(false); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('spatial_plannings', function (Blueprint $table) { + $table->dropColumn('is_terbit'); + }); + } +}; diff --git a/resources/js/dashboards/bigdata.js b/resources/js/dashboards/bigdata.js index a74e3df..53bf3f1 100644 --- a/resources/js/dashboards/bigdata.js +++ b/resources/js/dashboards/bigdata.js @@ -535,16 +535,14 @@ class BigData { }); } initChartNonBusinessDLH() { - document - .querySelectorAll("#non-business-dlh-count") - .forEach((element) => { - const count = this.safeGet( - this.resumeBigData, - "non_business_dlh_count", - 0 - ); - element.innerText = `${count}`; - }); + document.querySelectorAll("#business-dlh-count").forEach((element) => { + const count = this.safeGet( + this.resumeBigData, + "business_dlh_count", + 0 + ); + element.innerText = `${count}`; + }); } } diff --git a/resources/js/data/spatialPlannings/data-spatialPlannings.js b/resources/js/data/spatialPlannings/data-spatialPlannings.js index 86a201d..4f10d95 100644 --- a/resources/js/data/spatialPlannings/data-spatialPlannings.js +++ b/resources/js/data/spatialPlannings/data-spatialPlannings.js @@ -3,6 +3,7 @@ import gridjs from "gridjs/dist/gridjs.umd.js"; import "gridjs/dist/gridjs.umd.js"; import GlobalConfig, { addThousandSeparators } from "../../global-config.js"; import GeneralTable from "../../table-generator.js"; +import moment from "moment"; // Ambil hak akses dari data-attribute const tableElement = document.getElementById("spatial-planning-data-table"); @@ -15,7 +16,11 @@ const dataSpatialPlanningColumns = [ "Nama", "KBLI", "Kegiatan", - "Luas", + "Luas Lahan", + "BCR", + "Jenis Usaha", + "Status Terbit", + "Retribusi", "Lokasi", "Nomor", "Tanggal", @@ -23,7 +28,7 @@ const dataSpatialPlanningColumns = [ name: "Actions", widht: "120px", formatter: function (cell, row) { - const id = row.cells[8].data; + const id = row.cells[12].data; const model = "data/web-spatial-plannings"; let actionButtons = '
'; @@ -73,15 +78,27 @@ document.addEventListener("DOMContentLoaded", () => { table.processData = function (data) { return data.data.map((item) => { + // Format retribution amount + const retributionAmount = item.calculated_retribution + ? addThousandSeparators(item.calculated_retribution) + : "0"; + + // Format business type + const businessType = item.is_business_type ? "USAHA" : "NON USAHA"; + return [ item.no, item.name, item.kbli, item.activities, - addThousandSeparators(item.area), + addThousandSeparators(item.land_area || item.area), + addThousandSeparators(item.site_bcr), + `${businessType}`, + item.is_terbit ? "Sudah Terbit" : "Belum Terbit", + `${retributionAmount}`, item.location, item.number, - item.date, + moment(item.date).format("YYYY-MM-DD"), item.id, ]; }); diff --git a/resources/js/data/spatialPlannings/form-create-update.js b/resources/js/data/spatialPlannings/form-create-update.js index b66d5c7..9621b88 100644 --- a/resources/js/data/spatialPlannings/form-create-update.js +++ b/resources/js/data/spatialPlannings/form-create-update.js @@ -9,6 +9,9 @@ document.addEventListener("DOMContentLoaded", function () { if (!saveButton || !form) return; + // Initialize is_terbit toggle + initIsTerbitToggle(); + saveButton.addEventListener("click", function () { // Disable tombol dan tampilkan spinner modalButton.disabled = true; @@ -29,6 +32,12 @@ document.addEventListener("DOMContentLoaded", function () { data[key] = value; }); + // Handle checkbox properly - ensure boolean value is sent + const isTerbitCheckbox = document.getElementById("is_terbit"); + if (isTerbitCheckbox) { + data["is_terbit"] = isTerbitCheckbox.checked ? 1 : 0; + } + const url = form.getAttribute("action"); const method = isEdit ? "PUT" : "POST"; @@ -183,4 +192,29 @@ document.addEventListener("DOMContentLoaded", function () { document.querySelector(".btn-back").addEventListener("click", function () { window.history.back(); }); + + // Function to handle is_terbit toggle + function initIsTerbitToggle() { + const checkbox = document.getElementById("is_terbit"); + const statusText = document.querySelector(".status-text"); + const statusDescription = statusText?.nextElementSibling; + + if (checkbox && statusText) { + checkbox.addEventListener("change", function () { + if (this.checked) { + statusText.textContent = "Sudah Terbit"; + if (statusDescription) { + statusDescription.textContent = + "Status PBG sudah diterbitkan"; + } + } else { + statusText.textContent = "Belum Terbit"; + if (statusDescription) { + statusDescription.textContent = + "Status PBG belum diterbitkan"; + } + } + }); + } + } }); diff --git a/resources/views/dashboards/bigdata.blade.php b/resources/views/dashboards/bigdata.blade.php index f7e974d..ccfd1e2 100644 --- a/resources/views/dashboards/bigdata.blade.php +++ b/resources/views/dashboards/bigdata.blade.php @@ -91,16 +91,16 @@
-
@@ -114,23 +114,23 @@
-
diff --git a/resources/views/data/spatialPlannings/form.blade.php b/resources/views/data/spatialPlannings/form.blade.php index 0bf5008..d5f3ec8 100644 --- a/resources/views/data/spatialPlannings/form.blade.php +++ b/resources/views/data/spatialPlannings/form.blade.php @@ -1,5 +1,76 @@ @extends('layouts.vertical', ['subtitle' => $subtitle]) +@section('css') + +@endsection + @section('content') @include('layouts.partials/page-title', ['title' => $title, 'subtitle' => $subtitle]) @@ -38,38 +109,83 @@
@foreach($fields as $field => $label) -
- - @php - $fieldType = $fieldTypes[$field] ?? 'text'; // Default text jika tidak ditemukan tipe - @endphp + @if($field == 'is_terbit') + +
+ +
+ is_terbit ? 'checked' : '') }}> + +
+ + +
+ @elseif($field == 'calculated_retribution' && isset($modelInstance)) + +
+ +
+ {{ $modelInstance->formatted_retribution ?? '0' }} +
+ + Rumus: LUAS LAHAN × BCR (decimal) × HARGA SATUAN
+ Detail: {{ $modelInstance->land_area ?? 0 }} m² × {{ ($modelInstance->site_bcr ?? 0) / 100 }} × + + {{ $modelInstance->is_business_type ? 'Rp 44.300 (USAHA)' : 'Rp 16.000 (NON USAHA)' }} + +
+
+ @elseif($field == 'business_type_info' && isset($modelInstance)) + +
+ +
+ + {{ $modelInstance->is_business_type ? 'USAHA' : 'NON USAHA' }} + +
+ Terdeteksi otomatis dari fungsi bangunan: "{{ $modelInstance->building_function ?? $modelInstance->activities ?? 'N/A' }}" +
+ @else +
+ + @php + $fieldType = $fieldTypes[$field] ?? 'text'; // Default text jika tidak ditemukan tipe + @endphp - @if($fieldType == 'textarea') - - @elseif($fieldType == 'select' && isset($dropdownOptions[$field])) - - @elseif($fieldType == 'combobox' && isset($dropdownOptions[$field])) - - - @elseif($fieldType == 'date') - - @else - - @endif -
+ @if($fieldType == 'textarea') + + @elseif($fieldType == 'select' && isset($dropdownOptions[$field])) + + @elseif($fieldType == 'combobox' && isset($dropdownOptions[$field])) + + + @elseif($fieldType == 'date') + + @else + + @endif +
+ @endif @endforeach
diff --git a/resources/views/pbg_task/index.blade.php b/resources/views/pbg_task/index.blade.php index dd22d3e..89c1a4e 100644 --- a/resources/views/pbg_task/index.blade.php +++ b/resources/views/pbg_task/index.blade.php @@ -73,10 +73,7 @@
-