add spatial plannings retribution calculations
This commit is contained in:
295
app/Http/Controllers/RetributionProposalController.php
Normal file
295
app/Http/Controllers/RetributionProposalController.php
Normal file
@@ -0,0 +1,295 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\RetributionProposal;
|
||||
use App\Models\SpatialPlanning;
|
||||
use App\Models\BuildingFunction;
|
||||
use App\Services\RetributionProposalService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class RetributionProposalController extends Controller
|
||||
{
|
||||
protected RetributionProposalService $proposalService;
|
||||
|
||||
public function __construct(RetributionProposalService $proposalService)
|
||||
{
|
||||
$this->proposalService = $proposalService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of retribution proposals
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = RetributionProposal::with(['spatialPlanning', 'buildingFunction', 'retributionFormula']);
|
||||
|
||||
// Filtering
|
||||
if ($request->has('building_function_id')) {
|
||||
$query->where('building_function_id', $request->building_function_id);
|
||||
}
|
||||
|
||||
if ($request->has('spatial_planning_id')) {
|
||||
$query->where('spatial_planning_id', $request->spatial_planning_id);
|
||||
}
|
||||
|
||||
if ($request->has('floor_number')) {
|
||||
$query->where('floor_number', $request->floor_number);
|
||||
}
|
||||
|
||||
if ($request->has('has_spatial_planning')) {
|
||||
if ($request->boolean('has_spatial_planning')) {
|
||||
$query->whereNotNull('spatial_planning_id');
|
||||
} else {
|
||||
$query->whereNull('spatial_planning_id');
|
||||
}
|
||||
}
|
||||
|
||||
// Search
|
||||
if ($request->has('search')) {
|
||||
$search = $request->search;
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('proposal_number', 'like', "%{$search}%")
|
||||
->orWhere('notes', 'like', "%{$search}%")
|
||||
->orWhereHas('spatialPlanning', function ($sq) use ($search) {
|
||||
$sq->where('name', 'like', "%{$search}%");
|
||||
})
|
||||
->orWhereHas('buildingFunction', function ($bq) use ($search) {
|
||||
$bq->where('name', 'like', "%{$search}%");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Sorting
|
||||
$sortBy = $request->get('sort_by', 'created_at');
|
||||
$sortOrder = $request->get('sort_order', 'desc');
|
||||
$query->orderBy($sortBy, $sortOrder);
|
||||
|
||||
// Pagination
|
||||
$perPage = $request->get('per_page', 15);
|
||||
$proposals = $query->paginate($perPage);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $proposals,
|
||||
'meta' => [
|
||||
'total_amount' => RetributionProposal::sum('total_retribution_amount'),
|
||||
'total_proposals' => RetributionProposal::count(),
|
||||
'formatted_total_amount' => 'Rp ' . number_format(RetributionProposal::sum('total_retribution_amount'), 0, ',', '.')
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new retribution proposal
|
||||
*/
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'spatial_planning_id' => 'nullable|exists:spatial_plannings,id',
|
||||
'building_function_id' => 'required|exists:building_functions,id',
|
||||
'floor_number' => 'required|integer|min:1|max:10',
|
||||
'floor_area' => 'required|numeric|min:0.01',
|
||||
'total_building_area' => 'nullable|numeric|min:0.01',
|
||||
'notes' => 'nullable|string|max:1000'
|
||||
]);
|
||||
|
||||
try {
|
||||
if ($request->spatial_planning_id) {
|
||||
$spatialPlanning = SpatialPlanning::findOrFail($request->spatial_planning_id);
|
||||
$proposal = $this->proposalService->createProposalForSpatialPlanning(
|
||||
$spatialPlanning,
|
||||
$request->building_function_id,
|
||||
$request->floor_number,
|
||||
$request->floor_area,
|
||||
$request->total_building_area,
|
||||
$request->notes
|
||||
);
|
||||
} else {
|
||||
$proposal = $this->proposalService->createStandaloneProposal(
|
||||
$request->building_function_id,
|
||||
$request->floor_number,
|
||||
$request->floor_area,
|
||||
$request->total_building_area,
|
||||
$request->notes
|
||||
);
|
||||
}
|
||||
|
||||
$proposal->load(['spatialPlanning', 'buildingFunction', 'retributionFormula']);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Retribution proposal created successfully',
|
||||
'data' => $proposal
|
||||
], 201);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Failed to create retribution proposal',
|
||||
'error' => $e->getMessage()
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified retribution proposal
|
||||
*/
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
$proposal = RetributionProposal::with(['spatialPlanning', 'buildingFunction', 'retributionFormula'])
|
||||
->findOrFail($id);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $proposal
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified retribution proposal
|
||||
*/
|
||||
public function update(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$proposal = RetributionProposal::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'notes' => 'nullable|string|max:1000'
|
||||
]);
|
||||
|
||||
$proposal->update($request->only(['notes']));
|
||||
|
||||
$proposal->load(['spatialPlanning', 'buildingFunction', 'retributionFormula']);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Retribution proposal updated successfully',
|
||||
'data' => $proposal
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified retribution proposal
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$proposal = RetributionProposal::findOrFail($id);
|
||||
$proposal->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Retribution proposal deleted successfully'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get retribution proposal statistics
|
||||
*/
|
||||
public function statistics(): JsonResponse
|
||||
{
|
||||
$stats = $this->proposalService->getStatistics();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $stats
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total sum of all retribution proposals
|
||||
*/
|
||||
public function totalSum(): JsonResponse
|
||||
{
|
||||
$totalAmount = RetributionProposal::sum('total_retribution_amount');
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'total_amount' => $totalAmount,
|
||||
'formatted_total_amount' => 'Rp ' . number_format($totalAmount, 0, ',', '.'),
|
||||
'total_proposals' => RetributionProposal::count()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get building functions list
|
||||
*/
|
||||
public function buildingFunctions(): JsonResponse
|
||||
{
|
||||
$buildingFunctions = BuildingFunction::whereNotNull('parent_id')
|
||||
->with(['parameter'])
|
||||
->orderBy('name')
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $buildingFunctions
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-detect building function and create proposal
|
||||
*/
|
||||
public function autoCreateProposal(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'spatial_planning_id' => 'nullable|exists:spatial_plannings,id',
|
||||
'building_function_text' => 'required|string',
|
||||
'floor_number' => 'required|integer|min:1|max:10',
|
||||
'floor_area' => 'required|numeric|min:0.01',
|
||||
'total_building_area' => 'nullable|numeric|min:0.01',
|
||||
'notes' => 'nullable|string|max:1000'
|
||||
]);
|
||||
|
||||
try {
|
||||
// Auto-detect building function
|
||||
$buildingFunction = $this->proposalService->detectBuildingFunction($request->building_function_text);
|
||||
|
||||
if (!$buildingFunction) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Could not detect building function from text',
|
||||
'suggestion' => 'Please specify building function manually'
|
||||
], 400);
|
||||
}
|
||||
|
||||
if ($request->spatial_planning_id) {
|
||||
$spatialPlanning = SpatialPlanning::findOrFail($request->spatial_planning_id);
|
||||
$proposal = $this->proposalService->createProposalForSpatialPlanning(
|
||||
$spatialPlanning,
|
||||
$buildingFunction->id,
|
||||
$request->floor_number,
|
||||
$request->floor_area,
|
||||
$request->total_building_area,
|
||||
$request->notes
|
||||
);
|
||||
} else {
|
||||
$proposal = $this->proposalService->createStandaloneProposal(
|
||||
$buildingFunction->id,
|
||||
$request->floor_number,
|
||||
$request->floor_area,
|
||||
$request->total_building_area,
|
||||
$request->notes
|
||||
);
|
||||
}
|
||||
|
||||
$proposal->load(['spatialPlanning', 'buildingFunction', 'retributionFormula']);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Retribution proposal created successfully with auto-detected building function',
|
||||
'data' => $proposal,
|
||||
'detected_building_function' => $buildingFunction->name
|
||||
], 201);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Failed to create retribution proposal',
|
||||
'error' => $e->getMessage()
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user