Complete adaptation from BukidBountyApp to Philippine barangay governance: - Barangay models: Resident, Household, HouseholdMember, Blotter, BlotterHearing, DocumentRequest, RequestPayment, RequestType, BarangayProject, BarangayBudget - Controllers: ResidentController, HouseholdController, BlotterController, BlotterHearingController, DocumentRequestController, RequestTypeController, ProjectController, BudgetController, QRPHController, AdminConsoleController, UserController, FileController, ChapterController, LoginController - Vue pages: Home, ManageResidents, ResidentProfile, ManageHouseholds, ManageBlotters, BlotterDetail, RequestDocument, ManageDocumentRequests, DocumentRequestDetail, ManageRequestTypes, ManageProjects, BudgetLedger, AdminConsole - Barangay roles: PunongBarangay, Kagawad, Secretary, Treasurer, SK, Tanod, BHW, Staff, Resident - UserPermissions matrix rewritten with barangay-specific permission mappings - VueRouteMap replaced with barangay SPA routes - UserActions enum references corrected across all controllers - Removed all market/cooperative/POS/subscription code and models
242 lines
8.7 KiB
PHP
242 lines
8.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Http\Controllers\Helpers\ResponseHelper;
|
|
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
|
|
use App\Enums\UserActions;
|
|
use App\Models\Chapter;
|
|
use App\Models\ChapterMember;
|
|
use App\Models\User;
|
|
use App\Models\SystemSetting;
|
|
use App\Support\IslandGroupHelper;
|
|
use Hypervel\Http\Request;
|
|
use Hypervel\Support\Facades\Auth;
|
|
use Hypervel\Support\Facades\Validator;
|
|
use Hypervel\Support\Str;
|
|
|
|
class ChapterController
|
|
{
|
|
private const CHILD_LEVELS = [
|
|
'national' => ['region'],
|
|
'region' => ['province'],
|
|
'province' => ['city', 'municipal'],
|
|
'city' => ['barangay'],
|
|
'municipal' => ['barangay'],
|
|
'barangay' => ['purok'],
|
|
'purok' => [],
|
|
];
|
|
|
|
private function isAdmin(): bool
|
|
{
|
|
return UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::ManageChapterMembers);
|
|
}
|
|
|
|
public function hierarchy(Request $request)
|
|
{
|
|
$chapterId = $request->input('chapter_id');
|
|
|
|
if (!$chapterId) {
|
|
$national = Chapter::where('level', 'national')->where('location_key', 'philippines')->first();
|
|
if (!$national) {
|
|
return response()->json(['chapters' => [], 'current' => null, 'breadcrumb' => []]);
|
|
}
|
|
$chapters = $national->children()
|
|
->where('is_active', true)
|
|
->withCount('activeMembers')
|
|
->with('leaders.user')
|
|
->get()
|
|
->map(fn ($c) => $this->formatChapter($c))
|
|
->values();
|
|
|
|
return response()->json(['chapters' => $chapters, 'current' => null, 'breadcrumb' => []]);
|
|
}
|
|
|
|
$current = Chapter::withCount('activeMembers')->with('leaders.user')->find($chapterId);
|
|
if (!$current) return ResponseHelper::returnError('Chapter not found', 404);
|
|
|
|
$chapters = $current->children()
|
|
->where('is_active', true)
|
|
->withCount('activeMembers')
|
|
->with('leaders.user')
|
|
->get()
|
|
->map(fn ($c) => $this->formatChapter($c))
|
|
->values();
|
|
|
|
return response()->json([
|
|
'chapters' => $chapters,
|
|
'current' => $this->formatChapter($current),
|
|
'breadcrumb' => $this->buildBreadcrumb($current),
|
|
]);
|
|
}
|
|
|
|
public function mapData(Request $request)
|
|
{
|
|
$level = $request->input('level', 'region');
|
|
$parentId = $request->input('parent_id');
|
|
|
|
$query = Chapter::where('level', $level)->where('is_active', true)->withCount('activeMembers');
|
|
if ($parentId) $query->where('parent_id', $parentId);
|
|
|
|
$chapters = $query->get()
|
|
->filter(fn ($c) => $c->lat && $c->lng)
|
|
->map(fn ($c) => [
|
|
'id' => $c->id,
|
|
'name' => $c->name,
|
|
'level' => $c->level,
|
|
'lat' => $c->lat,
|
|
'lng' => $c->lng,
|
|
'count' => $c->active_members_count,
|
|
])
|
|
->values();
|
|
|
|
return response()->json(['chapters' => $chapters]);
|
|
}
|
|
|
|
public function members(Request $request)
|
|
{
|
|
$chapterId = $request->input('chapter_id');
|
|
if (!$chapterId) return ResponseHelper::returnError('chapter_id required', 400);
|
|
|
|
$members = ChapterMember::with('user')
|
|
->where('chapter_id', $chapterId)
|
|
->where('is_active', true)
|
|
->get()
|
|
->map(fn ($cm) => [
|
|
'hashkey' => $cm->hashkey,
|
|
'name' => $cm->user?->fullname ?? $cm->user?->name,
|
|
'position' => $cm->position,
|
|
'photo' => $cm->user?->photourl ?? null,
|
|
'is_manual' => (bool) $cm->is_manual_override,
|
|
]);
|
|
|
|
return response()->json(['members' => $members]);
|
|
}
|
|
|
|
public function assignMember(Request $request)
|
|
{
|
|
if (!$this->isAdmin()) return ResponseHelper::returnUnauthorized();
|
|
|
|
$validator = Validator::make($request->all(), [
|
|
'user_hashkey' => 'required|string',
|
|
'chapter_id' => 'required|integer',
|
|
'position' => 'nullable|string|max:100',
|
|
]);
|
|
|
|
if ($validator->fails()) return ResponseHelper::returnError('Validation failed', 422, $validator->errors());
|
|
|
|
$user = User::where('hashkey', $request->input('user_hashkey'))->first();
|
|
if (!$user) return ResponseHelper::returnError('User not found', 404);
|
|
|
|
$chapter = Chapter::find($request->input('chapter_id'));
|
|
if (!$chapter) return ResponseHelper::returnError('Chapter not found', 404);
|
|
|
|
$existing = ChapterMember::where('user_id', $user->id)->where('chapter_id', $chapter->id)->first();
|
|
|
|
if ($existing) {
|
|
$existing->update([
|
|
'position' => $request->input('position'),
|
|
'is_manual_override' => true,
|
|
'assigned_by' => Auth::id(),
|
|
'assigned_at' => now(),
|
|
'updated_by' => Auth::id(),
|
|
]);
|
|
} else {
|
|
ChapterMember::create([
|
|
'hashkey' => (string) Str::uuid(),
|
|
'user_id' => $user->id,
|
|
'chapter_id' => $chapter->id,
|
|
'position' => $request->input('position'),
|
|
'is_manual_override' => true,
|
|
'is_active' => true,
|
|
'assigned_by' => Auth::id(),
|
|
'assigned_at' => now(),
|
|
'created_by' => Auth::id(),
|
|
]);
|
|
}
|
|
|
|
return response()->json(['success' => true]);
|
|
}
|
|
|
|
public function removeMember(Request $request)
|
|
{
|
|
if (!$this->isAdmin()) return ResponseHelper::returnUnauthorized();
|
|
|
|
$member = ChapterMember::where('hashkey', $request->input('hashkey'))->first();
|
|
if (!$member) return ResponseHelper::returnError('Member assignment not found', 404);
|
|
|
|
$member->update(['is_active' => false, 'updated_by' => Auth::id()]);
|
|
|
|
return response()->json(['success' => true]);
|
|
}
|
|
|
|
public function positions()
|
|
{
|
|
$raw = SystemSetting::getValue('chapter_positions');
|
|
$positions = is_string($raw) ? (json_decode($raw, true) ?? []) : [];
|
|
if (empty($positions)) {
|
|
$positions = ['Punong Barangay', 'Kagawad', 'Secretary', 'Treasurer', 'SK Chairperson', 'SK Councilor', 'Tanod', 'BHW', 'Daycare Worker', 'Staff', 'Member'];
|
|
}
|
|
return response()->json(['positions' => $positions]);
|
|
}
|
|
|
|
public function createChapter(Request $request)
|
|
{
|
|
if (!$this->isAdmin()) return ResponseHelper::returnUnauthorized();
|
|
|
|
$validator = Validator::make($request->all(), [
|
|
'name' => 'required|string|max:255',
|
|
'level' => 'required|in:national,region,province,city,municipal,barangay,purok',
|
|
'parent_id' => 'nullable|integer|exists:chapters,id',
|
|
'location_key' => 'nullable|string|max:255',
|
|
'lat' => 'nullable|numeric',
|
|
'lng' => 'nullable|numeric',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return response()->json(['success' => false, 'errors' => $validator->errors()], 422);
|
|
}
|
|
|
|
$data = $validator->validated();
|
|
$data['hashkey'] = hash('sha256', uniqid((string) now(), true));
|
|
$data['is_active'] = true;
|
|
$data['created_by'] = Auth::id();
|
|
$data['updated_by'] = Auth::id();
|
|
$data['location_key'] = strtolower(trim($data['location_key'] ?? $data['name']));
|
|
|
|
$chapter = Chapter::create($data);
|
|
|
|
return response()->json(['success' => true, 'data' => $this->formatChapter($chapter), 'message' => 'Chapter created']);
|
|
}
|
|
|
|
private function formatChapter(Chapter $c): array
|
|
{
|
|
return [
|
|
'id' => $c->id,
|
|
'hashkey' => $c->hashkey,
|
|
'name' => $c->name,
|
|
'level' => $c->level,
|
|
'parent_id' => $c->parent_id,
|
|
'location_key' => $c->location_key,
|
|
'lat' => $c->lat,
|
|
'lng' => $c->lng,
|
|
'is_active' => $c->is_active,
|
|
'member_count' => $c->active_members_count ?? 0,
|
|
'child_levels' => self::CHILD_LEVELS[$c->level] ?? [],
|
|
];
|
|
}
|
|
|
|
private function buildBreadcrumb(Chapter $chapter): array
|
|
{
|
|
$crumbs = [];
|
|
$current = $chapter;
|
|
while ($current) {
|
|
array_unshift($crumbs, ['id' => $current->id, 'name' => $current->name, 'level' => $current->level]);
|
|
$current = $current->parent;
|
|
}
|
|
return $crumbs;
|
|
}
|
|
}
|