194 lines
7.7 KiB
PHP
194 lines
7.7 KiB
PHP
<?php
|
|
|
|
namespace App\Controllers\Administrator;
|
|
|
|
use App\Controllers\BaseController;
|
|
use App\Models\FinancialAidEstimateModel;
|
|
use App\Models\FinancialAidRequestModel;
|
|
use App\Models\InvoiceModel;
|
|
use App\Models\StudentModel;
|
|
use App\Models\UserModel;
|
|
use InvalidArgumentException;
|
|
use Throwable;
|
|
|
|
class FinancialAidController extends BaseController
|
|
{
|
|
public function index()
|
|
{
|
|
$schoolYear = $this->request->getGet('school_year');
|
|
$model = new FinancialAidRequestModel();
|
|
$builder = $model->orderBy('created_at', 'DESC');
|
|
if (is_string($schoolYear) && trim($schoolYear) !== '') {
|
|
$builder->where('school_year', trim($schoolYear));
|
|
}
|
|
|
|
$requests = $builder->findAll();
|
|
$parentIds = array_values(array_unique(array_filter(array_map('intval', array_column($requests, 'parent_id')))));
|
|
$parents = [];
|
|
if ($parentIds !== []) {
|
|
foreach ((new UserModel())->select('id, firstname, lastname, email')->whereIn('id', $parentIds)->findAll() as $parent) {
|
|
$parents[(int) $parent['id']] = $parent;
|
|
}
|
|
}
|
|
|
|
return view('administrator/financial_aid_queue', [
|
|
'requests' => $requests,
|
|
'parents' => $parents,
|
|
'schoolYear' => is_string($schoolYear) ? trim($schoolYear) : '',
|
|
]);
|
|
}
|
|
|
|
public function show(int $id)
|
|
{
|
|
$request = (new FinancialAidRequestModel())->find($id);
|
|
if ($request === null) {
|
|
return redirect()->to('/administrator/financial-aid')->with('error', 'Financial aid request was not found.');
|
|
}
|
|
|
|
$parent = (new UserModel())->find((int) $request['parent_id']);
|
|
$studentIds = json_decode((string) ($request['student_ids_json'] ?? '[]'), true);
|
|
$studentIds = is_array($studentIds) ? array_map('intval', $studentIds) : [];
|
|
$students = $studentIds !== []
|
|
? (new StudentModel())->whereIn('id', $studentIds)->findAll()
|
|
: [];
|
|
|
|
$schoolYear = (string) ($request['school_year'] ?? '');
|
|
$invoiceBalance = $this->invoiceBalanceForParent((int) ($request['parent_id'] ?? 0), $schoolYear);
|
|
$householdSize = max(1, (int) ($request['household_size'] ?? 1));
|
|
$householdIncome = (float) ($request['household_income'] ?? 0);
|
|
$requestedAmount = (float) ($request['requested_amount'] ?? 0);
|
|
$estimateModel = new FinancialAidEstimateModel();
|
|
$estimatedAid = $estimateModel->estimatedAid($invoiceBalance, $householdSize, $householdIncome);
|
|
$finalRebate = $estimateModel->finalRebate($invoiceBalance, $householdSize, $householdIncome, $requestedAmount);
|
|
|
|
return view('administrator/financial_aid_review', [
|
|
'requestRow' => $request,
|
|
'parent' => $parent,
|
|
'students' => $students,
|
|
'schoolYear' => $schoolYear,
|
|
'invoiceBalance' => $invoiceBalance,
|
|
'estimatedAid' => $estimatedAid,
|
|
'finalRebate' => $finalRebate,
|
|
]);
|
|
}
|
|
|
|
public function estimate(int $id)
|
|
{
|
|
$request = (new FinancialAidRequestModel())->find($id);
|
|
if ($request === null) {
|
|
return $this->response->setStatusCode(404)->setJSON(['error' => 'Financial aid request was not found.']);
|
|
}
|
|
|
|
$householdIncomeRaw = trim((string) $this->request->getPost('household_income'));
|
|
$householdSizeRaw = (int) $this->request->getPost('household_size');
|
|
$schoolYear = (string) ($request['school_year'] ?? '');
|
|
$invoiceBalance = $this->invoiceBalanceForParent((int) ($request['parent_id'] ?? 0), $schoolYear);
|
|
|
|
if ($householdIncomeRaw === '' || ! is_numeric($householdIncomeRaw) || (float) $householdIncomeRaw < 0) {
|
|
return $this->response->setStatusCode(422)->setJSON(['error' => 'Enter a valid household income.']);
|
|
}
|
|
if ($householdSizeRaw < 1) {
|
|
return $this->response->setStatusCode(422)->setJSON(['error' => 'Household size must be at least 1.']);
|
|
}
|
|
|
|
try {
|
|
$estimateModel = new FinancialAidEstimateModel();
|
|
$householdIncome = round((float) $householdIncomeRaw, 2);
|
|
$estimatedAid = $estimateModel->estimatedAid($invoiceBalance, $householdSizeRaw, $householdIncome);
|
|
$finalRebate = $estimateModel->finalRebate(
|
|
$invoiceBalance,
|
|
$householdSizeRaw,
|
|
$householdIncome,
|
|
(float) ($request['requested_amount'] ?? 0)
|
|
);
|
|
|
|
return $this->response->setJSON([
|
|
'invoice_balance' => $invoiceBalance,
|
|
'estimated_aid' => $estimatedAid,
|
|
'final_rebate' => $finalRebate,
|
|
'csrf_token' => csrf_token(),
|
|
'csrf_hash' => csrf_hash(),
|
|
]);
|
|
} catch (InvalidArgumentException $e) {
|
|
return $this->response->setStatusCode(422)->setJSON(['error' => $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
public function approve(int $id)
|
|
{
|
|
try {
|
|
$model = new FinancialAidRequestModel();
|
|
$request = $model->find($id);
|
|
if ($request === null) {
|
|
return redirect()->to('/administrator/financial-aid')->with('error', 'Financial aid request was not found.');
|
|
}
|
|
if (! in_array((string) ($request['status'] ?? ''), ['submitted', 'under_review'], true)) {
|
|
return redirect()->back()->with('error', 'Only open requests can be approved.');
|
|
}
|
|
|
|
$amount = $this->approvalAmount($request);
|
|
$note = trim((string) $this->request->getPost('admin_note'));
|
|
service('financialAid')->applyApprovedAmount($request, $amount, (int) session()->get('user_id'), $note);
|
|
|
|
return redirect()->to('/administrator/financial-aid')->with('success', 'Financial aid was approved and applied to the invoice.');
|
|
} catch (Throwable $e) {
|
|
return redirect()->back()->withInput()->with('error', $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function deny(int $id)
|
|
{
|
|
$model = new FinancialAidRequestModel();
|
|
$request = $model->find($id);
|
|
if ($request === null) {
|
|
return redirect()->to('/administrator/financial-aid')->with('error', 'Financial aid request was not found.');
|
|
}
|
|
if (! in_array((string) ($request['status'] ?? ''), ['submitted', 'under_review'], true)) {
|
|
return redirect()->back()->with('error', 'Only open requests can be denied.');
|
|
}
|
|
|
|
$note = trim((string) $this->request->getPost('admin_note'));
|
|
if ($note === '') {
|
|
return redirect()->back()->with('error', 'A denial note is required.');
|
|
}
|
|
|
|
$model->update($id, [
|
|
'status' => 'denied',
|
|
'admin_note' => $note,
|
|
'reviewed_by' => (int) session()->get('user_id'),
|
|
'reviewed_at' => date('Y-m-d H:i:s'),
|
|
]);
|
|
|
|
return redirect()->to('/administrator/financial-aid')->with('success', 'Financial aid request was denied.');
|
|
}
|
|
|
|
private function approvalAmount(array $request): float
|
|
{
|
|
$postedAmount = trim((string) $this->request->getPost('admin_amount'));
|
|
if ($postedAmount !== '') {
|
|
return (float) $postedAmount;
|
|
}
|
|
|
|
return (float) ($request['requested_amount'] ?? 0);
|
|
}
|
|
|
|
private function invoiceBalanceForParent(int $parentId, string $schoolYear): float
|
|
{
|
|
if ($parentId <= 0 || $schoolYear === '') {
|
|
return 0.0;
|
|
}
|
|
|
|
$invoice = (new InvoiceModel())
|
|
->where('parent_id', $parentId)
|
|
->where('school_year', $schoolYear)
|
|
->orderBy('id', 'DESC')
|
|
->first();
|
|
|
|
if ($invoice === null) {
|
|
return 0.0;
|
|
}
|
|
|
|
return round((float) ($invoice['balance'] ?? 0), 2);
|
|
}
|
|
}
|