tutoring/app/Http/Controllers/Admin/StudentController.php

362 lines
12 KiB
PHP

<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\StudentType;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use App\Models\StudentProfile;
use App\Models\BillingAccount;
use App\Models\ParentProfile;
class StudentController extends Controller
{
public function index()
{
$students = StudentProfile::with(['user', 'billingAccount'])->get();
return view('admin.students.index', compact('students'));
}
public function create()
{
$parents = ParentProfile::with('user')->get();
$studentTypes = StudentType::all();
return view('admin.students.create', compact('parents', 'studentTypes'));
}
public function edit(StudentProfile $student)
{
$student->load(['user', 'billingAccount', 'billingAccount.primaryParent']);
$parents = ParentProfile::with('user')->get();
$studentTypes = StudentType::all();
return view('admin.students.edit', compact('student', 'parents', 'studentTypes'));
}
public function update(Request $request, StudentProfile $student)
{
$validated = $request->validate([
// Student
'student_first_name' => 'required|string|max:255',
'student_last_name' => 'required|string|max:255',
'student_phone' => 'nullable|string|max:255',
// If you allow changing student email:
// 'student_email' => ['required','email', Rule::unique('users','email')->ignore($student->user_id)],
'date_of_birth' => 'nullable|date',
'student_type_id' => 'required|exists:student_types,id',
// Parent selection
'parent_option' => 'required|in:none,existing,new',
'existing_parent_id' => 'required_if:parent_option,existing|nullable|exists:parent_profiles,id',
// New parent (only used if parent_option=new)
'parent_first_name' => 'required_if:parent_option,new|nullable|string|max:255',
'parent_last_name' => 'required_if:parent_option,new|nullable|string|max:255',
'parent_email' => 'required_if:parent_option,new|nullable|email|unique:users,email',
'parent_phone' => 'nullable|string|max:255',
// Billing (match your edit form; keep minimal initially)
'billing_account_id' => 'sometimes|nullable|exists:billing_accounts,id',
'billing_name' => 'required|string|max:255',
'invoice_email' => 'required|email',
'billing_phone' => 'nullable|string|max:255',
'contact_name' => 'nullable|string|max:255',
'address_line1' => 'required|string|max:255',
'address_line2' => 'nullable|string|max:255',
'town' => 'required|string|max:255',
'postcode' => 'required|string|max:50',
'country' => 'required|string|max:255',
]);
DB::beginTransaction();
try {
// Load student user
$student->load('user');
// 1) Update STUDENT USER
$student->user->update([
'first_name' => $validated['student_first_name'],
'last_name' => $validated['student_last_name'],
'phone' => $validated['student_phone'] ?? null,
// 'email' => $validated['student_email'],
]);
// 2) Update STUDENT PROFILE
$student->update([
'date_of_birth' => $validated['date_of_birth'] ?? null,
'student_type_id' => $validated['student_type_id'],
// billing_account_id handled below
]);
// 3) Resolve parent user based on parent_option
$parentProfile = null;
if ($validated['parent_option'] === 'existing') {
$parentProfile = ParentProfile::with('user')->find($validated['existing_parent_id']);
}
if ($validated['parent_option'] === 'new') {
$parentUser = User::create([
'first_name' => $validated['parent_first_name'],
'last_name' => $validated['parent_last_name'],
'email' => $validated['parent_email'],
'phone' => $validated['parent_phone'],
'password' => Hash::make(str()->random(16)),
]);
$parentUser->assignRole('parent');
$parentProfile = ParentProfile::firstOrCreate(
['user_id' => $parentUser->id],
['phone' => $parentUser->phone]
);
// ensure $parentProfile has user loaded for later
$parentProfile->load('user');
}
if ($parentProfile && $parentProfile->user) {
// ensure role even for the "existing" case
$parentProfile->user->assignRole('parent');
}
// 4) Billing account: update existing or create new (same logic as store)
if (!empty($validated['billing_account_id'])) {
$billingAccount = BillingAccount::findOrFail($validated['billing_account_id']);
$billingAccount->update([
'name' => $validated['billing_name'],
'contact_name' => $validated['contact_name'],
'invoice_email' => $validated['invoice_email'],
'phone' => $validated['billing_phone'],
'address_line1' => $validated['address_line1'],
'address_line2' => $validated['address_line2'],
'town' => $validated['town'],
'postcode' => $validated['postcode'],
'country' => $validated['country'],
'primary_parent_user_id' => $parentProfile?->user_id,
]);
} else {
$billingAccount = BillingAccount::create([
'name' => $validated['billing_name'],
'contact_name' => $validated['contact_name'],
'invoice_email' => $validated['invoice_email'],
'phone' => $validated['billing_phone'],
'address_line1' => $validated['address_line1'],
'address_line2' => $validated['address_line2'],
'town' => $validated['town'],
'postcode' => $validated['postcode'],
'country' => $validated['country'],
'primary_parent_user_id' => $parentProfile?->user_id,
]);
}
if ($validated['parent_option'] === 'none') {
$billingAccount->update(['primary_parent_user_id' => null]);
}
// Ensure student profile points at the billing account we just resolved
$student->billing_account_id = $billingAccount->id;
$student->save();
// 5) Parent pivot handling
if ($validated['parent_option'] === 'none') {
$student->parents()->detach();
} else {
if ($parentProfile) {
// ONE parent only:
$student->parents()->sync([
$parentProfile->id => [
'relationship' => null,
'notes' => null,
],
]);
}
}
DB::commit();
return redirect()
->route('admin.students.edit', $student->id)
->with('success', 'Student updated successfully.');
} catch (\Exception $e) {
DB::rollBack();
throw $e;
}
}
public function store(Request $request)
{
// -----------------------------
// Validation
// -----------------------------
$validated = $request->validate([
// Student
'student_first_name' => 'required|string|max:255',
'student_last_name' => 'required|string|max:255',
'student_email' => 'required|email|unique:users,email',
'student_phone' => 'nullable|string|max:255',
'date_of_birth' => 'nullable|date',
'student_type_id' => 'required|exists:student_types,id',
// Parent selection
'parent_option' => 'required|in:none,existing,new',
'existing_parent_id' => 'required_if:parent_option,existing|nullable|exists:parent_profiles,id',
// New parent
'parent_first_name' => 'nullable|string|max:255',
'parent_last_name' => 'nullable|string|max:255',
'parent_email' => 'nullable|email|unique:users,email',
'parent_phone' => 'nullable|string|max:255',
// Billing
'billing_account_id' => 'sometimes|nullable|exists:billing_accounts,id',
'billing_name' => 'required|string|max:255',
'invoice_email' => 'required|email',
'billing_phone' => 'nullable|string|max:255',
'contact_name' => 'nullable|string|max:255',
'address_line1' => 'required|string|max:255',
'address_line2' => 'nullable|string|max:255',
'town' => 'required|string|max:255',
'postcode' => 'required|string|max:50',
'country' => 'required|string|max:255',
]);
DB::beginTransaction();
try {
// ===============================================================
// 1) Create STUDENT USER
// ===============================================================
$studentUser = User::create([
'first_name' => $validated['student_first_name'],
'last_name' => $validated['student_last_name'],
'email' => $validated['student_email'],
'phone' => $validated['student_phone'],
'password' => Hash::make(str()->random(16)), // Temporary password
]);
$studentUser->assignRole('student');
// ===============================================================
// 2) Handle PARENT selection
// ===============================================================
$parentProfile = null;
if ($validated['parent_option'] === 'existing') {
$parentProfile = ParentProfile::find($validated['existing_parent_id']);
}
if ($validated['parent_option'] === 'new') {
create([
'first_name' => $validated['parent_first_name'],
'last_name' => $validated['parent_last_name'],
'email' => $validated['parent_email'],
'phone' => $validated['parent_phone'],
'password' => Hash::make(str()->random(16)),
]);
$parentUser->assignRole('parent');
$parentProfile = ParentProfile::firstOrCreate(
['user_id' => $parentUser->id],
['phone' => $parentUser->phone]
);
}
if ($parentProfile) {
$parentProfile->user?->assignRole('parent');
}
// Note: If parent_option == 'none', $parentUser remains null.
// ===============================================================
// 3) Create BILLING ACCOUNT
// ===============================================================
if (!empty($validated['billing_account_id'])) {
// Use existing billing account
$billingAccount = BillingAccount::find($validated['billing_account_id']);
} else {
$billingAccount = BillingAccount::create([
'name' => $validated['billing_name'],
'contact_name' => $validated['contact_name'],
'invoice_email' => $validated['invoice_email'],
'phone' => $validated['billing_phone'],
'address_line1' => $validated['address_line1'],
'address_line2' => $validated['address_line2'],
'town' => $validated['town'],
'postcode' => $validated['postcode'],
'country' => $validated['country'],
'primary_parent_user_id' => $parentProfile?->user_id,
]);
}
// ===============================================================
// 4) Create STUDENT PROFILE
// ===============================================================
$studentProfile = StudentProfile::create([
'user_id' => $studentUser->id,
'date_of_birth' => $validated['date_of_birth'] ?? null,
'billing_account_id' => $billingAccount->id,
'student_type_id' => $validated['student_type_id'],
]);
// ===============================================================
// 4B) Create/link PARENT PROFILE + pivot relationship
// ===============================================================
if ($parentUser) {
// Ensure parent has role (covers "existing parent" case)
$parentUser->assignRole('parent');
// Ensure parent profile exists
$parentProfile = ParentProfile::firstOrCreate(
['user_id' => $parentUser->id],
['phone' => $parentUser->phone] // optional default
);
// Link parent profile to student profile via pivot
$studentProfile->parents()->syncWithoutDetaching([
$parentProfile->id => [
'relationship' => null,
'notes' => null,
],
]);
}
// ===============================================================
// 5) Send password setup email to student user
// ===============================================================
Password::sendResetLink(['email' => $studentUser->email]);
DB::commit();
return redirect()
->route('admin.students.index')
->with('success', 'Student created successfully.');
} catch (\Exception $e) {
DB::rollBack();
throw $e; // (You can customise error messages later)
}
}
}