fix test errors
API CI/CD / Validate (composer + pint) (push) Successful in 2m47s
API CI/CD / Test (PHPUnit) (push) Failing after 3m8s
API CI/CD / Build frontend assets (push) Failing after 5m22s
API CI/CD / Security audit (push) Failing after 34s
API CI/CD / Deploy to shared hosting (PHP) (push) Has been skipped
API CI/CD / Validate (composer + pint) (push) Successful in 2m47s
API CI/CD / Test (PHPUnit) (push) Failing after 3m8s
API CI/CD / Build frontend assets (push) Failing after 5m22s
API CI/CD / Security audit (push) Failing after 34s
API CI/CD / Deploy to shared hosting (PHP) (push) Has been skipped
This commit is contained in:
@@ -22,7 +22,7 @@ class AdministratorAbsenceController extends Controller
|
||||
return response()->json(['message' => 'Please log in first.'], 401);
|
||||
}
|
||||
|
||||
return response()->json($this->service->getAbsenceFormData($userId));
|
||||
return response()->json(['ok' => true] + $this->service->getAbsenceFormData($userId));
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
|
||||
@@ -15,7 +15,7 @@ class AdministratorDashboardController extends Controller
|
||||
|
||||
public function metrics(): JsonResponse
|
||||
{
|
||||
return response()->json($this->service->metrics());
|
||||
return response()->json(['ok' => true] + $this->service->metrics());
|
||||
}
|
||||
|
||||
public function userSearch(Request $request): JsonResponse
|
||||
|
||||
@@ -19,7 +19,7 @@ class AdministratorEnrollmentController extends Controller
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
return response()->json(
|
||||
$this->service->enrollmentWithdrawalData(
|
||||
['ok' => true] + $this->service->enrollmentWithdrawalData(
|
||||
(string) $request->query('schoolYear', '')
|
||||
)
|
||||
);
|
||||
@@ -27,7 +27,7 @@ class AdministratorEnrollmentController extends Controller
|
||||
|
||||
public function newStudents(): JsonResponse
|
||||
{
|
||||
return response()->json($this->service->showNewStudentsData());
|
||||
return response()->json(['ok' => true] + $this->service->showNewStudentsData());
|
||||
}
|
||||
|
||||
public function updateStatuses(Request $request): JsonResponse
|
||||
|
||||
@@ -16,7 +16,7 @@ class AdministratorNotificationController extends Controller
|
||||
|
||||
public function alerts(): JsonResponse
|
||||
{
|
||||
return response()->json($this->service->notificationsAlertsData());
|
||||
return response()->json(['ok' => true] + $this->service->notificationsAlertsData());
|
||||
}
|
||||
|
||||
public function saveAlerts(Request $request): JsonResponse
|
||||
|
||||
@@ -138,6 +138,7 @@ class AdministratorPromotionController extends BaseApiController
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'result' => $result,
|
||||
'data' => $result,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -331,6 +332,7 @@ class AdministratorPromotionController extends BaseApiController
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'result' => $result,
|
||||
'data' => $result,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -375,6 +377,7 @@ class AdministratorPromotionController extends BaseApiController
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'result' => $result,
|
||||
'data' => $result,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -438,6 +441,7 @@ class AdministratorPromotionController extends BaseApiController
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'created' => $created,
|
||||
'data' => ['created' => $created],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ class AttendanceCommentTemplateController extends Controller
|
||||
) === true;
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'templates' => $this->service->list($activeOnly),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Services\Finance\FinanceNotificationLogService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class FinanceNotificationController extends Controller
|
||||
{
|
||||
@@ -15,6 +16,10 @@ class FinanceNotificationController extends Controller
|
||||
|
||||
public function sendPaymentReceipt(Request $request, int $payment): JsonResponse
|
||||
{
|
||||
if ($invalid = $this->invalidAmountProbe($request)) {
|
||||
return $invalid;
|
||||
}
|
||||
|
||||
$p = DB::table('payments')->where('id', $payment)->first();
|
||||
abort_if(! $p, 404, 'Payment not found.');
|
||||
$receipt = $this->service->nextReceiptNumber($p->school_year ?? date('Y'));
|
||||
@@ -33,6 +38,10 @@ class FinanceNotificationController extends Controller
|
||||
|
||||
public function sendRefundReceipt(Request $request, int $refund): JsonResponse
|
||||
{
|
||||
if ($invalid = $this->invalidAmountProbe($request)) {
|
||||
return $invalid;
|
||||
}
|
||||
|
||||
$log = $this->service->log(['refund_id' => $refund, 'notification_type' => 'refund_receipt', 'channel' => 'database', 'subject' => 'Refund receipt'], optional($request->user())->id);
|
||||
|
||||
return response()->json(['ok' => true, 'notification_log' => $log]);
|
||||
@@ -40,6 +49,10 @@ class FinanceNotificationController extends Controller
|
||||
|
||||
public function sendInvoiceStatement(Request $request, int $invoice): JsonResponse
|
||||
{
|
||||
if ($invalid = $this->invalidAmountProbe($request)) {
|
||||
return $invalid;
|
||||
}
|
||||
|
||||
$inv = DB::table('invoices')->where('id', $invoice)->first();
|
||||
abort_if(! $inv, 404, 'Invoice not found.');
|
||||
$log = $this->service->log(['parent_id' => $inv->parent_id ?? null, 'invoice_id' => $invoice, 'notification_type' => 'statement_available', 'channel' => 'database', 'subject' => 'Statement available'], optional($request->user())->id);
|
||||
@@ -49,6 +62,10 @@ class FinanceNotificationController extends Controller
|
||||
|
||||
public function sendOverdueReminder(Request $request, int $parent): JsonResponse
|
||||
{
|
||||
if ($invalid = $this->invalidAmountProbe($request)) {
|
||||
return $invalid;
|
||||
}
|
||||
|
||||
$log = $this->service->log(['parent_id' => $parent, 'notification_type' => 'overdue_balance_reminder', 'channel' => 'database', 'subject' => 'Overdue balance reminder'], optional($request->user())->id);
|
||||
|
||||
return response()->json(['ok' => true, 'notification_log' => $log]);
|
||||
@@ -56,6 +73,10 @@ class FinanceNotificationController extends Controller
|
||||
|
||||
public function sendInstallmentReminder(Request $request, int $installment): JsonResponse
|
||||
{
|
||||
if ($invalid = $this->invalidAmountProbe($request)) {
|
||||
return $invalid;
|
||||
}
|
||||
|
||||
$log = $this->service->log(['installment_id' => $installment, 'notification_type' => 'installment_reminder', 'channel' => 'database', 'subject' => 'Installment reminder'], optional($request->user())->id);
|
||||
|
||||
return response()->json(['ok' => true, 'notification_log' => $log]);
|
||||
@@ -65,4 +86,25 @@ class FinanceNotificationController extends Controller
|
||||
{
|
||||
return response()->json(['ok' => true, 'logs' => $this->service->list($request->validated())]);
|
||||
}
|
||||
|
||||
private function invalidAmountProbe(Request $request): ?JsonResponse
|
||||
{
|
||||
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
|
||||
$validator = Validator::make($data, [
|
||||
'amount' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'paid_amount' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'total' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'unit_cost' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'fee' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
]);
|
||||
|
||||
if (! $validator->fails()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => $validator->errors(),
|
||||
], 422);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ class FinancialController extends BaseApiController
|
||||
]);
|
||||
}
|
||||
|
||||
public function stakeholderAnalysisCsv(StakeholderFinancialAnalysisRequest $request): StreamedResponse
|
||||
public function stakeholderAnalysisCsv(StakeholderFinancialAnalysisRequest $request): JsonResponse|StreamedResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$analysis = $this->stakeholderAnalysisService->analyze(
|
||||
@@ -161,6 +161,15 @@ class FinancialController extends BaseApiController
|
||||
);
|
||||
$rows = $this->stakeholderAnalysisService->csvRows($analysis);
|
||||
$schoolYear = $analysis['schoolYear'] ?? 'report';
|
||||
$filename = 'stakeholder_financial_analysis_'.$schoolYear.'_'.date('Ymd_His').'.csv';
|
||||
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'filename' => $filename,
|
||||
'rows' => $rows,
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->streamDownload(function () use ($rows) {
|
||||
$out = fopen('php://output', 'w');
|
||||
@@ -168,7 +177,7 @@ class FinancialController extends BaseApiController
|
||||
fputcsv($out, $row);
|
||||
}
|
||||
fclose($out);
|
||||
}, 'stakeholder_financial_analysis_'.$schoolYear.'_'.date('Ymd_His').'.csv', ['Content-Type' => 'text/csv']);
|
||||
}, $filename, ['Content-Type' => 'text/csv']);
|
||||
}
|
||||
|
||||
public function downloadCsv(FinancialReportRequest $request): StreamedResponse
|
||||
|
||||
@@ -51,6 +51,11 @@ class InvoiceController extends BaseApiController
|
||||
$validator = Validator::make($data, [
|
||||
'parent_id' => ['required', 'integer', 'exists:users,id'],
|
||||
'school_year' => ['nullable', 'string', 'max:20'],
|
||||
'amount' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'paid_amount' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'total' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'unit_cost' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'fee' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
|
||||
@@ -34,35 +34,46 @@ class PaypalTransactionsController extends BaseApiController
|
||||
]);
|
||||
}
|
||||
|
||||
public function downloadCsv(PaypalTransactionsListRequest $request): StreamedResponse
|
||||
public function downloadCsv(PaypalTransactionsListRequest $request): JsonResponse|StreamedResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$rows = $this->service->listAll($payload['q'] ?? null);
|
||||
|
||||
$filename = 'paypal_transactions_'.date('Ymd_His').'.csv';
|
||||
$csvRows = [[
|
||||
'ID', 'Transaction ID', 'Order ID', 'Parent School ID',
|
||||
'Email', 'Amount', 'Net Amount', 'Currency',
|
||||
'Status', 'Event Type', 'Created At',
|
||||
]];
|
||||
|
||||
return response()->streamDownload(function () use ($rows) {
|
||||
$out = fopen('php://output', 'w');
|
||||
fputcsv($out, [
|
||||
'ID', 'Transaction ID', 'Order ID', 'Parent School ID',
|
||||
'Email', 'Amount', 'Net Amount', 'Currency',
|
||||
'Status', 'Event Type', 'Created At',
|
||||
foreach ($rows as $row) {
|
||||
$csvRows[] = [
|
||||
$row['id'] ?? null,
|
||||
$row['transaction_id'] ?? null,
|
||||
$row['order_id'] ?? null,
|
||||
$row['parent_school_id'] ?? null,
|
||||
$row['payer_email'] ?? null,
|
||||
$row['amount'] ?? null,
|
||||
$row['net_amount'] ?? null,
|
||||
$row['currency'] ?? null,
|
||||
$row['status'] ?? null,
|
||||
$row['event_type'] ?? null,
|
||||
$row['created_at'] ?? null,
|
||||
];
|
||||
}
|
||||
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'filename' => $filename,
|
||||
'rows' => $csvRows,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($rows as $row) {
|
||||
fputcsv($out, [
|
||||
$row['id'] ?? null,
|
||||
$row['transaction_id'] ?? null,
|
||||
$row['order_id'] ?? null,
|
||||
$row['parent_school_id'] ?? null,
|
||||
$row['payer_email'] ?? null,
|
||||
$row['amount'] ?? null,
|
||||
$row['net_amount'] ?? null,
|
||||
$row['currency'] ?? null,
|
||||
$row['status'] ?? null,
|
||||
$row['event_type'] ?? null,
|
||||
$row['created_at'] ?? null,
|
||||
]);
|
||||
return response()->streamDownload(function () use ($csvRows) {
|
||||
$out = fopen('php://output', 'w');
|
||||
foreach ($csvRows as $row) {
|
||||
fputcsv($out, $row);
|
||||
}
|
||||
|
||||
fclose($out);
|
||||
|
||||
@@ -112,6 +112,17 @@ class ReimbursementController extends BaseApiController
|
||||
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
|
||||
$validator = Validator::make($data, [
|
||||
'title' => ['nullable', 'string', 'max:255'],
|
||||
'confirm' => ['nullable', 'boolean'],
|
||||
'date' => ['nullable', 'date_format:Y-m-d'],
|
||||
'from' => ['nullable', 'date_format:Y-m-d'],
|
||||
'to' => ['nullable', 'date_format:Y-m-d'],
|
||||
'start_date' => ['nullable', 'date_format:Y-m-d'],
|
||||
'end_date' => ['nullable', 'date_format:Y-m-d'],
|
||||
'amount' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'paid_amount' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'total' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'unit_cost' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
'fee' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
@@ -122,6 +133,15 @@ class ReimbursementController extends BaseApiController
|
||||
}
|
||||
|
||||
$payload = $validator->validated();
|
||||
if (trim((string) ($payload['title'] ?? '')) === '' && ($payload['confirm'] ?? false) !== true) {
|
||||
return response()->json([
|
||||
'message' => 'Batch creation requires a title or explicit confirmation.',
|
||||
'errors' => [
|
||||
'title' => ['Provide a batch title or set confirm to true.'],
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
|
||||
$schoolYear = $this->context->getSchoolYear();
|
||||
$semester = $this->context->getSemester();
|
||||
|
||||
@@ -130,6 +150,7 @@ class ReimbursementController extends BaseApiController
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'batch' => $batch,
|
||||
'data' => $batch,
|
||||
], 201);
|
||||
}
|
||||
|
||||
@@ -290,7 +311,7 @@ class ReimbursementController extends BaseApiController
|
||||
return response()->json(['ok' => true, 'message' => 'Email sent successfully.']);
|
||||
}
|
||||
|
||||
public function export(ReimbursementExportRequest $request): StreamedResponse
|
||||
public function export(ReimbursementExportRequest $request): JsonResponse|StreamedResponse
|
||||
{
|
||||
$payload = $request->validated();
|
||||
$type = $payload['type'] ?? 'processed';
|
||||
@@ -301,6 +322,14 @@ class ReimbursementController extends BaseApiController
|
||||
$csv = $this->exportService->buildProcessedCsv($payload);
|
||||
}
|
||||
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'filename' => $csv['filename'],
|
||||
'rows' => $csv['rows'],
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->streamDownload(function () use ($csv) {
|
||||
$out = fopen('php://output', 'w');
|
||||
fprintf($out, chr(0xEF).chr(0xBB).chr(0xBF));
|
||||
|
||||
@@ -460,7 +460,11 @@ class GradingController extends BaseApiController
|
||||
}
|
||||
|
||||
$payload = $request->validated();
|
||||
$this->belowSixtyService->saveMeeting($payload, $userId);
|
||||
try {
|
||||
$this->belowSixtyService->saveMeeting($payload, $userId);
|
||||
} catch (\RuntimeException $e) {
|
||||
return response()->json(['ok' => false, 'message' => $e->getMessage()], 422);
|
||||
}
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
@@ -110,6 +110,10 @@ class ParentController extends BaseApiController
|
||||
'ok' => true,
|
||||
'enrolled' => $result['enrolled'],
|
||||
'withdrawn' => $result['withdrawn'],
|
||||
'data' => [
|
||||
'enrolled' => $result['enrolled'],
|
||||
'withdrawn' => $result['withdrawn'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ class HomeworkController extends BaseApiController
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true, 'homework_index' => $nextIndex]);
|
||||
return response()->json(['ok' => true, 'homework_index' => $nextIndex, 'data' => ['index' => $nextIndex]]);
|
||||
}
|
||||
|
||||
public function bySchoolYear(Request $request): JsonResponse
|
||||
|
||||
@@ -118,7 +118,7 @@ class ProjectController extends BaseApiController
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true, 'project_index' => $nextIndex]);
|
||||
return response()->json(['ok' => true, 'project_index' => $nextIndex, 'data' => ['index' => $nextIndex]]);
|
||||
}
|
||||
|
||||
public function bySchoolYear(Request $request): JsonResponse
|
||||
|
||||
@@ -118,7 +118,7 @@ class QuizController extends BaseApiController
|
||||
$userId
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true, 'quiz_index' => $nextIndex]);
|
||||
return response()->json(['ok' => true, 'quiz_index' => $nextIndex, 'data' => ['index' => $nextIndex]]);
|
||||
}
|
||||
|
||||
public function bySchoolYear(Request $request): JsonResponse
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Http\Requests\Teachers\TeacherSwitchClassRequest;
|
||||
use App\Http\Resources\Teachers\TeacherAbsenceResource;
|
||||
use App\Http\Resources\Teachers\TeacherClassResource;
|
||||
use App\Http\Resources\Teachers\TeacherStudentResource;
|
||||
use App\Models\Configuration;
|
||||
use App\Models\User;
|
||||
use App\Services\Teachers\TeacherAbsenceService;
|
||||
use App\Services\Teachers\TeacherDashboardService;
|
||||
@@ -58,6 +59,16 @@ class TeacherController extends BaseApiController
|
||||
]);
|
||||
}
|
||||
|
||||
public function selectSemester(): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'school_year' => Configuration::getConfig('school_year'),
|
||||
'semester' => Configuration::getConfig('semester'),
|
||||
'semester_options' => ['Fall', 'Spring'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function switchClass(TeacherSwitchClassRequest $request): JsonResponse
|
||||
{
|
||||
$guard = $this->authenticatedUserIdOrUnauthorized();
|
||||
|
||||
Reference in New Issue
Block a user