add family logic
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Family;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Requests\Families\FamilyAdminCardRequest;
|
||||
use App\Http\Requests\Families\FamilyAdminIndexRequest;
|
||||
use App\Http\Requests\Families\FamilyAdminSearchRequest;
|
||||
use App\Http\Requests\Families\FamilyComposeEmailRequest;
|
||||
use App\Http\Resources\Families\FamilyResource;
|
||||
use App\Http\Resources\Families\FamilySearchItemResource;
|
||||
use App\Models\Configuration;
|
||||
use App\Services\Families\FamilyNotificationService;
|
||||
use App\Services\Families\FamilyQueryService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class FamilyAdminController extends BaseApiController
|
||||
{
|
||||
public function __construct(
|
||||
private FamilyQueryService $queryService,
|
||||
private FamilyNotificationService $notificationService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function index(FamilyAdminIndexRequest $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$schoolYear = trim((string) (Configuration::getConfig('school_year') ?? ''));
|
||||
|
||||
$data = $this->queryService->adminIndexData(
|
||||
$payload['student_id'] ?? null,
|
||||
$payload['guardian_id'] ?? null,
|
||||
$schoolYear
|
||||
);
|
||||
|
||||
return $this->success([
|
||||
'student' => $data['student'],
|
||||
'families' => FamilyResource::collection($data['families']),
|
||||
'guardians' => $data['guardians'],
|
||||
'students' => $data['students'],
|
||||
'searchStudents' => $data['searchStudents'],
|
||||
'searchGuardians' => $data['searchGuardians'],
|
||||
'resolved_student_id' => $data['resolved_student_id'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function search(FamilyAdminSearchRequest $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$items = $this->queryService->searchSuggestions(
|
||||
(string) $payload['q'],
|
||||
(int) ($payload['limit'] ?? 8)
|
||||
);
|
||||
|
||||
return $this->success([
|
||||
'items' => FamilySearchItemResource::collection($items),
|
||||
]);
|
||||
}
|
||||
|
||||
public function card(FamilyAdminCardRequest $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$schoolYear = trim((string) (Configuration::getConfig('school_year') ?? ''));
|
||||
|
||||
$family = $this->queryService->familyCard(
|
||||
$payload['student_id'] ?? null,
|
||||
$payload['guardian_id'] ?? null,
|
||||
$payload['family_id'] ?? null,
|
||||
$schoolYear
|
||||
);
|
||||
|
||||
if (!$family) {
|
||||
return $this->error('Family not found.', Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
return $this->success(new FamilyResource($family));
|
||||
}
|
||||
|
||||
public function composeEmail(FamilyComposeEmailRequest $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
|
||||
$ok = $this->notificationService->sendComposeEmail(
|
||||
(string) $payload['recipient'],
|
||||
(string) $payload['subject'],
|
||||
(string) $payload['html_message'],
|
||||
$payload['profile'] ?? null,
|
||||
$payload['reply_to_email'] ?? null,
|
||||
$payload['reply_to_name'] ?? null
|
||||
);
|
||||
|
||||
if (!$ok) {
|
||||
Log::warning('Compose email failed for family admin', ['recipient' => $payload['recipient']]);
|
||||
return $this->error('Unable to send email.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return $this->success(['recipient' => $payload['recipient']], 'Email sent.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Family;
|
||||
|
||||
use App\Http\Controllers\Api\BaseApiController;
|
||||
use App\Http\Requests\Families\FamiliesByStudentRequest;
|
||||
use App\Http\Requests\Families\FamilyAttachSecondByEmailRequest;
|
||||
use App\Http\Requests\Families\FamilyAttachSecondByUserRequest;
|
||||
use App\Http\Requests\Families\FamilyBootstrapRequest;
|
||||
use App\Http\Requests\Families\FamilyImportLegacyRequest;
|
||||
use App\Http\Requests\Families\FamilySetGuardianFlagsRequest;
|
||||
use App\Http\Requests\Families\FamilySetPrimaryHomeRequest;
|
||||
use App\Http\Requests\Families\FamilyUnlinkGuardianRequest;
|
||||
use App\Http\Requests\Families\FamilyUnlinkStudentRequest;
|
||||
use App\Http\Requests\Families\GuardiansByFamilyRequest;
|
||||
use App\Http\Resources\Families\FamilyGuardianResource;
|
||||
use App\Http\Resources\Families\FamilyResource;
|
||||
use App\Services\Families\FamilyMutationService;
|
||||
use App\Services\Families\FamilyQueryService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class FamilyController extends BaseApiController
|
||||
{
|
||||
public function __construct(
|
||||
private FamilyQueryService $queryService,
|
||||
private FamilyMutationService $mutationService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function familiesByStudent(FamiliesByStudentRequest $request, int $studentId): JsonResponse
|
||||
{
|
||||
$rows = $this->queryService->listFamiliesByStudent($studentId);
|
||||
|
||||
return $this->success([
|
||||
'families' => FamilyResource::collection($rows),
|
||||
]);
|
||||
}
|
||||
|
||||
public function guardiansByFamily(GuardiansByFamilyRequest $request, int $familyId): JsonResponse
|
||||
{
|
||||
$rows = $this->queryService->listGuardiansByFamily($familyId);
|
||||
|
||||
return $this->success([
|
||||
'guardians' => FamilyGuardianResource::collection($rows),
|
||||
]);
|
||||
}
|
||||
|
||||
public function bootstrap(FamilyBootstrapRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$result = $this->mutationService->bootstrapFamilies();
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Family bootstrap failed: ' . $e->getMessage());
|
||||
return $this->error('Family bootstrap failed.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return $this->success($result, 'Bootstrap completed.');
|
||||
}
|
||||
|
||||
public function attachSecondByUser(FamilyAttachSecondByUserRequest $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$result = $this->mutationService->attachSecondByUser(
|
||||
(int) $payload['student_id'],
|
||||
(int) $payload['user_id'],
|
||||
(string) ($payload['relation'] ?? 'secondary')
|
||||
);
|
||||
|
||||
if (!($result['ok'] ?? false)) {
|
||||
return $this->error($result['message'] ?? 'Unable to attach guardian.', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
return $this->success($result, 'Guardian attached.');
|
||||
}
|
||||
|
||||
public function attachSecondByEmail(FamilyAttachSecondByEmailRequest $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
try {
|
||||
$result = $this->mutationService->attachSecondByEmail(
|
||||
(int) $payload['student_id'],
|
||||
(string) $payload['email'],
|
||||
$payload['firstname'] ?? null,
|
||||
$payload['lastname'] ?? null,
|
||||
(string) ($payload['relation'] ?? 'secondary')
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Attach guardian by email failed: ' . $e->getMessage());
|
||||
return $this->error('Unable to attach guardian.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
if (!($result['ok'] ?? false)) {
|
||||
return $this->error($result['message'] ?? 'Unable to attach guardian.', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
return $this->success($result, 'Guardian attached.');
|
||||
}
|
||||
|
||||
public function setPrimaryHome(FamilySetPrimaryHomeRequest $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$this->mutationService->setPrimaryHome(
|
||||
(int) $payload['family_id'],
|
||||
(int) $payload['student_id'],
|
||||
(bool) $payload['is_primary_home']
|
||||
);
|
||||
|
||||
return $this->success(null, 'Primary home updated.');
|
||||
}
|
||||
|
||||
public function setGuardianFlags(FamilySetGuardianFlagsRequest $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$flags = array_intersect_key($payload, array_flip(['receive_emails', 'is_primary', 'receive_sms', 'relation']));
|
||||
|
||||
if (empty($flags)) {
|
||||
return $this->error('No flags provided.', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
$this->mutationService->setGuardianFlags(
|
||||
(int) $payload['family_id'],
|
||||
(int) $payload['user_id'],
|
||||
$flags
|
||||
);
|
||||
|
||||
return $this->success(null, 'Guardian flags updated.');
|
||||
}
|
||||
|
||||
public function unlinkGuardian(FamilyUnlinkGuardianRequest $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$this->mutationService->unlinkGuardian(
|
||||
(int) $payload['family_id'],
|
||||
(int) $payload['user_id']
|
||||
);
|
||||
|
||||
return $this->success(null, 'Guardian unlinked.');
|
||||
}
|
||||
|
||||
public function unlinkStudent(FamilyUnlinkStudentRequest $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$this->mutationService->unlinkStudent(
|
||||
(int) $payload['family_id'],
|
||||
(int) $payload['student_id']
|
||||
);
|
||||
|
||||
return $this->success(null, 'Student unlinked.');
|
||||
}
|
||||
|
||||
public function importSecondParentsFromLegacy(FamilyImportLegacyRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$result = $this->mutationService->importSecondParentsFromLegacy();
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Legacy second parent import failed: ' . $e->getMessage());
|
||||
return $this->error('Legacy import failed.', Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
if (!($result['ok'] ?? true)) {
|
||||
return $this->error($result['message'] ?? 'Legacy import failed.', Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
return $this->success($result, 'Legacy import completed.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user