383 lines
14 KiB
PHP
Executable File
383 lines
14 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Models\Configuration;
|
|
use App\Models\Event;
|
|
use App\Models\EventCharges;
|
|
use App\Models\Student;
|
|
use App\Models\User;
|
|
use App\Http\Controllers\Api\InvoiceController;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class EventController extends BaseApiController
|
|
{
|
|
protected Event $event;
|
|
protected Configuration $config;
|
|
protected EventCharges $eventCharges;
|
|
protected Student $student;
|
|
protected User $user;
|
|
protected InvoiceController $invoiceController;
|
|
protected ?string $schoolYear;
|
|
protected ?string $semester;
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
$this->event = model(Event::class);
|
|
$this->config = model(Configuration::class);
|
|
$this->eventCharges = model(EventCharges::class);
|
|
$this->student = model(Student::class);
|
|
$this->user = model(User::class);
|
|
$this->invoiceController = app(InvoiceController::class);
|
|
|
|
$this->schoolYear = $this->config->getConfig('school_year');
|
|
$this->semester = $this->config->getConfig('semester');
|
|
}
|
|
|
|
public function index()
|
|
{
|
|
$schoolYear = $this->request->getGet('school_year') ?? $this->schoolYear;
|
|
$upcomingOnly = $this->request->getGet('upcoming') === 'true';
|
|
|
|
$query = $this->event->newQuery();
|
|
if ($schoolYear) {
|
|
$query->where('school_year', $schoolYear);
|
|
}
|
|
if ($upcomingOnly) {
|
|
$today = Carbon::now()->toDateString();
|
|
$query->where('expiration_date', '>=', $today);
|
|
}
|
|
|
|
$events = $query->orderBy('created_at', 'DESC')->get()->toArray();
|
|
|
|
// Count active events
|
|
$today = Carbon::now()->toDateString();
|
|
$activeEventCount = $this->event->newQuery()
|
|
->where('expiration_date', '>=', $today)
|
|
->count();
|
|
|
|
return $this->success([
|
|
'events' => $events,
|
|
'active_event_count' => $activeEventCount,
|
|
], 'Events retrieved successfully');
|
|
}
|
|
|
|
public function show($id = null)
|
|
{
|
|
$event = $this->event->find($id);
|
|
if (!$event) {
|
|
return $this->respondError('Event not found', Response::HTTP_NOT_FOUND);
|
|
}
|
|
|
|
return $this->success($event, 'Event retrieved successfully');
|
|
}
|
|
|
|
public function create()
|
|
{
|
|
$data = $this->payloadData();
|
|
if (empty($data)) {
|
|
return $this->respondError('Invalid request data', Response::HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
$rules = [
|
|
'event_name' => 'required|max_length[255]',
|
|
'description' => 'nullable',
|
|
'amount' => 'required|numeric',
|
|
'expiration_date' => 'required|date',
|
|
'semester' => 'nullable',
|
|
'school_year' => 'nullable',
|
|
];
|
|
|
|
$errors = $this->validateRequest($data, $rules);
|
|
if (!empty($errors)) {
|
|
return $this->respondValidationError($errors);
|
|
}
|
|
|
|
$flyerPath = null;
|
|
|
|
// Handle file upload if present
|
|
if ($this->laravelRequest->hasFile('flyer')) {
|
|
$file = $this->laravelRequest->file('flyer');
|
|
if ($file->isValid()) {
|
|
$path = $file->store('event_flyers', 'public');
|
|
$flyerPath = $path;
|
|
}
|
|
}
|
|
|
|
$payload = [
|
|
'event_name' => $data['event_name'],
|
|
'description' => $data['description'] ?? null,
|
|
'amount' => $data['amount'],
|
|
'flyer' => $flyerPath,
|
|
'expiration_date' => $data['expiration_date'],
|
|
'semester' => $data['semester'] ?? $this->semester,
|
|
'school_year' => $data['school_year'] ?? $this->schoolYear,
|
|
'created_by' => $this->getCurrentUserId(),
|
|
];
|
|
|
|
try {
|
|
$event = $this->event->create($payload);
|
|
return $this->respondCreated($event->toArray(), 'Event created successfully');
|
|
} catch (\Throwable $e) {
|
|
Log::error('Event creation error: ' . $e->getMessage());
|
|
return $this->respondError('Failed to create event', Response::HTTP_INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
public function update($id = null)
|
|
{
|
|
$event = $this->event->find($id);
|
|
if (!$event) {
|
|
return $this->respondError('Event not found', Response::HTTP_NOT_FOUND);
|
|
}
|
|
|
|
$data = $this->payloadData();
|
|
if (empty($data)) {
|
|
return $this->respondError('Invalid request data', Response::HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
$flyerPath = $event['flyer']; // Keep existing flyer by default
|
|
|
|
// Handle file upload if present
|
|
if ($this->laravelRequest->hasFile('flyer')) {
|
|
$file = $this->laravelRequest->file('flyer');
|
|
if ($file->isValid()) {
|
|
// Delete old flyer if exists
|
|
if ($flyerPath && Storage::disk('public')->exists($flyerPath)) {
|
|
Storage::disk('public')->delete($flyerPath);
|
|
}
|
|
$path = $file->store('event_flyers', 'public');
|
|
$flyerPath = $path;
|
|
}
|
|
}
|
|
|
|
$updateData = [];
|
|
$allowed = ['event_name', 'description', 'amount', 'expiration_date', 'semester', 'school_year'];
|
|
foreach ($allowed as $field) {
|
|
if (array_key_exists($field, $data)) {
|
|
$updateData[$field] = $data[$field];
|
|
}
|
|
}
|
|
$updateData['flyer'] = $flyerPath;
|
|
|
|
try {
|
|
$this->event->update($id, $updateData);
|
|
$updated = $this->event->find($id);
|
|
return $this->success($updated->toArray(), 'Event updated successfully');
|
|
} catch (\Throwable $e) {
|
|
Log::error('Event update error: ' . $e->getMessage());
|
|
return $this->respondError('Failed to update event', Response::HTTP_INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
public function delete($id = null)
|
|
{
|
|
$event = $this->event->find($id);
|
|
if (!$event) {
|
|
return $this->respondError('Event not found', Response::HTTP_NOT_FOUND);
|
|
}
|
|
|
|
try {
|
|
// Delete related charges and collect parent IDs
|
|
$charges = $this->eventCharges->newQuery()
|
|
->where('event_id', $id)
|
|
->get()
|
|
->toArray();
|
|
|
|
$parentIds = [];
|
|
foreach ($charges as $charge) {
|
|
$this->eventCharges->delete($charge['id']);
|
|
$parentIds[] = $charge['parent_id'];
|
|
}
|
|
|
|
// Delete event
|
|
$this->event->delete($id);
|
|
|
|
$parentIds = array_unique($parentIds);
|
|
|
|
// Regenerate invoices for affected parents
|
|
// Note: generateInvoice method may need to be implemented in InvoiceController
|
|
foreach ($parentIds as $parentId) {
|
|
// This would need to be implemented or called differently
|
|
// $this->invoiceController->generateInvoice($parentId);
|
|
}
|
|
|
|
return $this->success(null, 'Event, charges, and invoices updated successfully');
|
|
} catch (\Throwable $e) {
|
|
Log::error('Event deletion error: ' . $e->getMessage());
|
|
return $this->respondError('Failed to delete event', Response::HTTP_INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET /api/v1/events/charges
|
|
* Returns event charges with parent and student information
|
|
*/
|
|
public function charges()
|
|
{
|
|
$schoolYear = $this->request->getGet('school_year') ?? $this->schoolYear;
|
|
$semester = $this->request->getGet('semester') ?? $this->semester;
|
|
|
|
try {
|
|
$parents = $this->user->getParents();
|
|
$events = $this->event->getActiveEvents($this->schoolYear);
|
|
|
|
$charges = $this->eventCharges->newQuery()
|
|
->select([
|
|
'event_charges.*',
|
|
'users.firstname AS parent_firstname',
|
|
'users.lastname AS parent_lastname',
|
|
'students.firstname AS student_firstname',
|
|
'students.lastname AS student_lastname',
|
|
'events.event_name'
|
|
])
|
|
->leftJoin('users', 'users.id', '=', 'event_charges.parent_id')
|
|
->leftJoin('students', 'students.id', '=', 'event_charges.student_id')
|
|
->leftJoin('events', 'events.id', '=', 'event_charges.event_id')
|
|
->where('event_charges.school_year', $schoolYear)
|
|
->where('event_charges.semester', $semester)
|
|
->orderBy('event_charges.created_at', 'DESC')
|
|
->get()
|
|
->toArray();
|
|
|
|
return $this->success([
|
|
'charges' => $charges,
|
|
'parents' => $parents,
|
|
'events' => $events,
|
|
'school_year' => $schoolYear,
|
|
'semester' => $semester,
|
|
], 'Event charges retrieved successfully');
|
|
} catch (\Throwable $e) {
|
|
Log::error('Event charges retrieval error: ' . $e->getMessage());
|
|
return $this->respondError('Failed to retrieve event charges', Response::HTTP_INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* POST /api/v1/events/charges/update
|
|
* Updates event charges for a parent and students
|
|
*/
|
|
public function updateCharges()
|
|
{
|
|
$data = $this->payloadData();
|
|
if (empty($data)) {
|
|
return $this->respondError('Invalid request data', Response::HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
$schoolYear = $data['school_year'] ?? $this->schoolYear;
|
|
$semester = $data['semester'] ?? $this->semester;
|
|
$parentId = $data['parent_id'] ?? null;
|
|
$eventId = $data['event_id'] ?? null;
|
|
$participations = $data['participation'] ?? [];
|
|
|
|
if (!$parentId || !$eventId || empty($participations)) {
|
|
return $this->respondError('Missing required information: parent_id, event_id, and participation are required', Response::HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
try {
|
|
$userId = $this->getCurrentUserId();
|
|
$event = $this->event->getEvent($eventId, $schoolYear);
|
|
|
|
if (!$event) {
|
|
return $this->respondError('Event not found', Response::HTTP_NOT_FOUND);
|
|
}
|
|
|
|
foreach ($participations as $studentId => $value) {
|
|
$existing = $this->eventCharges->newQuery()
|
|
->where('parent_id', $parentId)
|
|
->where('student_id', $studentId)
|
|
->where('event_id', $eventId)
|
|
->where('school_year', $schoolYear)
|
|
->where('semester', $semester)
|
|
->first();
|
|
|
|
if ($value === 'no') {
|
|
if ($existing) {
|
|
$this->eventCharges->delete($existing['id']);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// value is 'yes'
|
|
$chargeData = [
|
|
'parent_id' => $parentId,
|
|
'student_id' => $studentId,
|
|
'event_id' => $eventId,
|
|
'participation' => 'yes',
|
|
'charged' => $event['amount'],
|
|
'school_year' => $schoolYear,
|
|
'semester' => $semester,
|
|
];
|
|
|
|
if ($existing) {
|
|
$chargeData['updated_by'] = $userId;
|
|
$this->eventCharges->update($existing['id'], $chargeData);
|
|
} else {
|
|
$chargeData['updated_by'] = $userId;
|
|
$this->eventCharges->insert($chargeData);
|
|
}
|
|
}
|
|
|
|
// Regenerate invoice for parent
|
|
// Note: generateInvoice method may need to be implemented
|
|
// $this->invoiceController->generateInvoice($parentId);
|
|
|
|
return $this->success(null, 'Event charges updated successfully');
|
|
} catch (\Throwable $e) {
|
|
Log::error('Event charges update error: ' . $e->getMessage());
|
|
return $this->respondError('Failed to update event charges', Response::HTTP_INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET /api/v1/events/students-with-charges
|
|
* Returns students for a parent with their charge status
|
|
*/
|
|
public function getStudentsWithCharges()
|
|
{
|
|
$parentId = $this->request->getGet('parent_id');
|
|
$semester = $this->request->getGet('semester') ?? $this->semester;
|
|
$schoolYear = $this->request->getGet('school_year') ?? $this->schoolYear;
|
|
|
|
if (!$parentId) {
|
|
return $this->respondError('parent_id is required', Response::HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
try {
|
|
// Get students for parent
|
|
$students = $this->student->newQuery()
|
|
->where('parent_id', $parentId)
|
|
->get()
|
|
->toArray();
|
|
|
|
// Get student_ids that already have charges
|
|
$chargedStudentIds = $this->eventCharges->newQuery()
|
|
->where('parent_id', $parentId)
|
|
->where('semester', $semester)
|
|
->where('school_year', $schoolYear)
|
|
->groupBy('student_id')
|
|
->pluck('student_id')
|
|
->toArray();
|
|
|
|
$data = [];
|
|
foreach ($students as $student) {
|
|
$data[] = [
|
|
'id' => $student['id'],
|
|
'name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')),
|
|
'charged' => in_array($student['id'], $chargedStudentIds),
|
|
];
|
|
}
|
|
|
|
return $this->success($data, 'Students with charges retrieved successfully');
|
|
} catch (\Throwable $e) {
|
|
Log::error('Get students with charges error: ' . $e->getMessage());
|
|
return $this->respondError('Failed to retrieve students with charges', Response::HTTP_INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
}
|