From 6def9993dad5e52e42c41f68f2d80523acdfa8cb Mon Sep 17 00:00:00 2001 From: root Date: Tue, 9 Jun 2026 02:32:58 -0400 Subject: [PATCH] fix gitlab tests --- .../Commands/AttendanceAutoPublishCommand.php | 1 - .../Commands/CheckMissedPaymentsCommand.php | 2 - .../CleanupExpiredNotificationsCommand.php | 2 - .../Commands/CleanupPasswordResetsCommand.php | 1 - app/Console/Commands/ConfigUpdateCommand.php | 11 +- .../Commands/DeleteInactiveUsersCommand.php | 1 - .../Commands/DeleteUnverifiedUsersCommand.php | 1 - .../Commands/RecalculateAttendanceCommand.php | 3 +- .../Commands/SendAbsenteesSummaryCommand.php | 1 - .../Commands/SendLatesSummaryCommand.php | 1 - ...SendMonthlyPaymentNotificationsCommand.php | 10 +- .../SendTestPaymentNotificationCommand.php | 11 +- .../Commands/SyncPaypalPaymentsCommand.php | 3 +- app/Events/DeleteUnverifiedUser.php | 4 +- app/Events/WhatsappInvitesSend.php | 4 +- app/Helpers/app_helpers.php | 18 +- .../AdministratorAbsenceController.php | 5 +- .../AdministratorDashboardController.php | 5 +- .../AdministratorEnrollmentController.php | 7 +- .../AdministratorNotificationController.php | 7 +- .../AdministratorPromotionController.php | 30 +- ...ministratorTeacherSubmissionController.php | 3 +- .../EmergencyContactController.php | 7 +- .../TeacherClassAssignmentController.php | 3 + .../AdminAttendanceApiController.php | 6 +- .../AttendanceCommentTemplateController.php | 5 +- .../Attendance/EarlyDismissalsController.php | 83 +- .../Api/Attendance/LateSlipLogsController.php | 9 +- .../StaffAttendanceApiController.php | 18 +- .../TeacherAttendanceApiController.php | 15 +- .../AttendanceManagementController.php | 24 +- .../AttendanceTrackingController.php | 3 +- .../Controllers/Api/Auth/AuthController.php | 6 +- .../Controllers/Api/Auth/IpBanController.php | 15 +- .../Api/Auth/RegisterController.php | 3 +- .../Api/Auth/RolePermissionController.php | 41 +- .../Api/Auth/RoleSwitcherController.php | 5 +- .../Api/Auth/SessionTimeoutController.php | 3 +- .../Api/Badges/BadgeController.php | 10 +- .../Controllers/Api/BaseApiController.php | 4 +- .../ClassPreparationController.php | 8 +- .../ClassProgress/ClassProgressController.php | 22 +- .../Api/Classes/ClassController.php | 7 +- .../Communication/CommunicationController.php | 19 +- .../CompetitionScoresController.php | 16 +- .../Api/Core/BaseApiController.php | 82 +- .../Api/Discounts/DiscountController.php | 11 +- .../Api/Email/BroadcastEmailController.php | 9 +- .../Controllers/Api/Email/EmailController.php | 2 +- .../Api/Email/EmailExtractorController.php | 1 + .../Api/Exams/ExamDraftController.php | 9 +- .../Api/Expenses/ExpenseController.php | 12 +- .../ExtraCharges/ExtraChargesController.php | 9 +- .../Api/Family/FamilyAdminController.php | 5 +- .../Api/Family/FamilyController.php | 15 +- .../Finance/BalanceCarryforwardController.php | 9 +- .../Api/Finance/ChargeController.php | 3 + .../Api/Finance/EventChargeController.php | 69 +- .../Finance/FinanceNotificationController.php | 11 +- .../Api/Finance/FinancialController.php | 22 +- .../Api/Finance/InstallmentPlanController.php | 51 +- .../Api/Finance/InvoiceController.php | 7 +- .../Api/Finance/PaymentController.php | 2 +- .../Finance/PaymentEventChargesController.php | 3 + .../Api/Finance/PaymentManualController.php | 59 +- .../Finance/PaymentTransactionController.php | 2 +- .../Finance/PaypalTransactionsController.php | 2 +- .../Api/Finance/PurchaseOrderController.php | 10 +- .../Api/Finance/RefundController.php | 6 +- .../Api/Finance/ReimbursementController.php | 21 +- .../Api/Frontend/FrontendController.php | 2 +- .../Api/Frontend/InfoIconController.php | 3 + .../Api/Frontend/LandingPageController.php | 6 +- .../Api/Frontend/PageController.php | 2 +- .../Api/Grading/GradingController.php | 9 +- .../Api/Incidents/IncidentController.php | 4 + .../Inventory/InventoryCategoryController.php | 6 +- .../Api/Inventory/InventoryController.php | 24 +- .../Inventory/InventoryMovementController.php | 11 +- .../Api/Inventory/SupplierController.php | 6 +- .../Inventory/SupplyCategoryController.php | 6 +- .../Api/Messaging/MessagesController.php | 20 +- .../Api/Messaging/WhatsappController.php | 13 +- .../Notifications/NotificationController.php | 12 +- .../ParentAttendanceReportController.php | 7 +- .../Api/Parents/ParentController.php | 4 +- .../Api/Parents/ParentPromotionController.php | 8 +- .../PrintRequests/PrintRequestsController.php | 3 +- .../Api/Reports/ReportCardsController.php | 18 +- .../Api/Reports/SlipPrinterController.php | 11 +- .../Api/Reports/StickersController.php | 7 +- .../Api/RolePermissionController.php | 38 +- .../Api/RoleSwitcherController.php | 2 +- .../Controllers/Api/ScannerController.php | 82 +- .../Api/Scores/FinalController.php | 3 + .../Api/Scores/HomeworkController.php | 3 + .../Api/Scores/MidtermController.php | 3 + .../Api/Scores/ParticipationController.php | 3 + .../Api/Scores/ProjectController.php | 3 + .../Controllers/Api/Scores/QuizController.php | 3 + .../Api/Scores/ScoreCommentController.php | 7 +- .../Api/Scores/ScoreController.php | 3 + .../Settings/ConfigurationAdminController.php | 6 +- .../Api/Settings/EventController.php | 6 +- .../Api/Settings/PreferencesController.php | 18 +- .../Api/Settings/SchoolCalendarController.php | 24 +- .../Api/Settings/SettingsController.php | 6 +- .../Controllers/Api/Staff/StaffController.php | 20 +- .../Api/Staff/TeacherController.php | 7 +- app/Http/Controllers/Api/StatsController.php | 8 +- .../Api/Students/StudentController.php | 85 +- .../Subjects/SubjectCurriculumController.php | 6 +- .../Api/Support/SupportController.php | 8 +- .../Api/System/DashboardController.php | 2 +- .../System/DashboardRedirectController.php | 5 +- .../Api/System/DatabaseHealthController.php | 2 +- .../Api/System/NavBuilderController.php | 7 +- .../Api/System/StatsController.php | 7 +- app/Http/Controllers/Api/Ui/UiController.php | 3 + .../Controllers/Api/Users/UserController.php | 3 + .../Web/SchoolYearAdminPageController.php | 3 +- .../Web/TeacherCalendarPageController.php | 3 +- app/Http/Middleware/ApiDocsAuth.php | 6 +- app/Http/Middleware/ApiJwtAuth.php | 2 +- app/Http/Middleware/CleanupScheduler.php | 4 +- .../EnsurePrintRequestsAdminAccess.php | 3 +- .../Middleware/EnsureSchoolYearEditable.php | 8 +- app/Http/Middleware/MultiAuth.php | 2 - app/Http/Middleware/PrimeTimezone.php | 4 +- app/Http/Middleware/RequirePermission.php | 7 +- .../Admin/SaveCompetitionScoresRequest.php | 3 +- .../Admin/UpdateCompetitionWinnerRequest.php | 4 +- .../SubmitAdministratorAbsenceRequest.php | 2 +- .../Api/Admin/IndexAdminProgressRequest.php | 3 +- .../SaveAdminNotificationSubjectsRequest.php | 4 +- ...SavePrintNotificationRecipientsRequest.php | 4 +- ...dTeacherSubmissionNotificationsRequest.php | 4 +- .../StoreStudentAssignmentRequest.php | 12 +- .../AdminAddAttendanceEntryRequest.php | 2 +- .../Attendance/SaveAdminAttendanceRequest.php | 2 +- .../SaveStaffAttendanceCellRequest.php | 2 +- .../TeacherSubmitAttendanceRequest.php | 2 +- .../UpdateAttendanceManagementRequest.php | 2 +- .../ComposeAttendanceEmailRequest.php | 6 +- .../RecordAttendanceTrackingRequest.php | 10 +- .../SaveAttendanceNotificationNoteRequest.php | 12 +- .../SendAttendanceManualEmailRequest.php | 12 +- app/Http/Requests/Auth/RegisterRequest.php | 2 +- .../Badges/BadgePrintStatusRequest.php | 4 +- .../Badges/GenerateBadgePdfRequest.php | 4 +- .../Requests/Badges/LogBadgePrintRequest.php | 4 +- .../ClassProgressIndexRequest.php | 4 +- .../ClassProgressMetaRequest.php | 2 + .../ClassProgressStoreRequest.php | 6 +- .../ClassProgressUpdateRequest.php | 8 +- .../Families/FamilyComposeEmailRequest.php | 2 +- .../Finance/CarryforwardAdjustmentRequest.php | 10 +- .../Finance/CarryforwardFinalizeRequest.php | 14 +- .../Finance/CarryforwardPreviewRequest.php | 14 +- .../Finance/EventChargeLifecycleRequest.php | 26 +- .../Finance/FinanceNotificationLogRequest.php | 16 +- .../Finance/FinancialSummaryRequest.php | 4 +- .../Requests/Finance/FollowUpNoteRequest.php | 24 +- .../Finance/InstallmentPlanRequest.php | 16 +- .../Finance/ParentPaymentFollowUpRequest.php | 32 +- .../Finance/PaymentAllocationRequest.php | 12 +- .../Incidents/IncidentStoreRequest.php | 2 +- .../Promotions/AdminListPromotionsRequest.php | 2 +- .../ParentEnrollmentStepRequest.php | 1 - .../PurchaseOrderStoreRequest.php | 2 +- .../Refunds/RefundDecisionRequest.php | 2 +- .../Requests/Refunds/RefundIndexRequest.php | 2 +- .../Stickers/StickerFormDataRequest.php | 2 +- .../Reports/Stickers/StickerPrintRequest.php | 4 +- .../StickerStudentsByClassRequest.php | 2 +- .../Requests/Roles/PermissionStoreRequest.php | 1 + app/Http/Requests/Security/IpBanRequest.php | 2 +- app/Http/Requests/Security/IpUnbanRequest.php | 2 +- .../Admin/AdminNotificationAlertsResource.php | 2 +- .../Admin/PrintRecipientsResource.php | 2 +- .../Admin/Progress/ProgressGroupResource.php | 2 +- .../Progress/ProgressReportDetailResource.php | 2 +- .../Admin/TeacherSubmissionReportResource.php | 2 +- .../Attendance/AdminAttendanceResource.php | 2 +- .../Attendance/DailyAttendanceResource.php | 2 +- .../TeacherAttendanceFormResource.php | 4 +- .../Attendance/TeacherGridResource.php | 4 +- .../ClassProgressGroupCollection.php | 4 +- .../Resources/Events/EventChargeResource.php | 4 +- .../Resources/Messaging/MessageCollection.php | 2 +- .../Resources/Messaging/MessageResource.php | 4 +- .../PaymentNotificationLogResource.php | 2 +- .../Promotions/StudentPromotionResource.php | 1 - .../ReimbursementRecipientResource.php | 2 +- app/Http/Resources/Staff/StaffCollection.php | 2 +- .../Support/SupportRequestCollection.php | 2 +- app/Http/Resources/System/NavItemResource.php | 2 +- .../TeacherSubmissionRowResource.php | 2 +- app/Libraries/StaffTimeOffLinkService.php | 4 +- .../AttendanceConsequenceListener.php | 4 +- app/Listeners/BelowSixtyEmailListener.php | 4 +- .../DeleteUnverifiedUserListener.php | 4 +- app/Listeners/SchoolEventListener.php | 3 +- app/Listeners/WhatsappInviteListener.php | 4 +- app/Mail/TeacherSubmissionReminderMail.php | 3 +- app/Models/AdditionalCharge.php | 21 +- app/Models/AdminNotificationSubject.php | 7 +- app/Models/AttendanceCommentTemplate.php | 4 +- app/Models/AttendanceData.php | 190 +- app/Models/AttendanceDay.php | 87 +- app/Models/AttendanceEmailTemplate.php | 4 +- app/Models/AttendanceRecord.php | 34 +- app/Models/AttendanceTracking.php | 158 +- app/Models/AuthorizedUser.php | 6 +- app/Models/BadgePrintLog.php | 70 +- app/Models/BaseModel.php | 20 +- app/Models/Calendar.php | 4 +- app/Models/CalendarEvent.php | 21 +- app/Models/ClassModel.php | 4 +- app/Models/ClassPrepAdjustment.php | 6 +- app/Models/ClassPreparationLog.php | 6 +- app/Models/ClassProgressAttachment.php | 6 +- app/Models/ClassProgressReport.php | 10 +- app/Models/ClassSection.php | 4 +- app/Models/Communication.php | 4 +- app/Models/CommunicationLog.php | 18 +- app/Models/Competition.php | 23 +- app/Models/CompetitionClassWinner.php | 12 +- app/Models/CompetitionScore.php | 10 +- app/Models/CompetitionWinner.php | 16 +- app/Models/Configuration.php | 10 +- app/Models/ContactUs.php | 6 +- app/Models/CurrentFlag.php | 14 +- app/Models/CurrentIncident.php | 3 +- app/Models/DiscountUsage.php | 15 +- app/Models/DiscountVoucher.php | 26 +- app/Models/EarlyDismissalSignature.php | 6 +- app/Models/EmailTemplate.php | 6 +- app/Models/EmergencyContact.php | 8 +- app/Models/Enrollment.php | 21 +- app/Models/Event.php | 29 +- app/Models/EventCharge.php | 4 +- app/Models/EventCharges.php | 19 +- app/Models/Exam.php | 9 +- app/Models/ExamDraft.php | 16 +- app/Models/Expense.php | 29 +- app/Models/Family.php | 4 +- app/Models/FamilyCommPref.php | 12 +- app/Models/FamilyGuardian.php | 14 +- app/Models/FamilyStudent.php | 9 +- app/Models/FinalExam.php | 22 +- app/Models/FinalScore.php | 12 +- app/Models/FinanceBalanceCarryforward.php | 2 - app/Models/FinanceFollowUpNote.php | 1 - app/Models/FinanceNotificationLog.php | 1 - app/Models/FinanceNotificationPreference.php | 1 - app/Models/FinanceReceiptSequence.php | 1 - app/Models/GradingLock.php | 11 +- app/Models/Homework.php | 39 +- app/Models/Incident.php | 10 +- app/Models/InventoryCategory.php | 4 +- app/Models/InventoryItem.php | 18 +- app/Models/InventoryMovement.php | 16 +- app/Models/Invoice.php | 52 +- app/Models/InvoiceEvent.php | 10 +- app/Models/InvoiceInstallment.php | 1 - app/Models/InvoiceInstallmentPlan.php | 1 - app/Models/InvoiceStudentList.php | 8 +- app/Models/IpAttempt.php | 9 +- app/Models/LateSlipLog.php | 36 +- app/Models/LoginActivity.php | 8 +- app/Models/ManualPayment.php | 6 +- app/Models/Message.php | 20 +- app/Models/MidtermExam.php | 22 +- app/Models/MissingScoreOverride.php | 39 +- app/Models/NavItem.php | 8 +- app/Models/Notification.php | 13 +- app/Models/ParentAttendanceReport.php | 25 +- app/Models/ParentMeetingSchedule.php | 12 +- app/Models/ParentModel.php | 4 +- app/Models/ParentNotification.php | 8 +- app/Models/Participation.php | 42 +- app/Models/PasswordReset.php | 5 +- app/Models/PasswordResetRequest.php | 4 +- app/Models/PayPalPayment.php | 15 +- app/Models/Payment.php | 47 +- app/Models/PaymentCarryforwardAllocation.php | 1 - app/Models/PaymentError.php | 16 +- app/Models/PaymentInstallmentAllocation.php | 1 - app/Models/PaymentNotificationLog.php | 26 +- app/Models/PaymentTransaction.php | 13 +- app/Models/PaypalTransaction.php | 12 +- app/Models/Permission.php | 9 +- app/Models/PlacementBatch.php | 4 +- app/Models/PlacementLevel.php | 4 +- app/Models/PlacementScore.php | 8 +- app/Models/Preferences.php | 16 +- app/Models/PrintRequest.php | 14 +- app/Models/Project.php | 27 +- app/Models/PromotionAuditLog.php | 11 - app/Models/PromotionQueue.php | 22 +- app/Models/PromotionReminderLog.php | 4 - app/Models/PurchaseOrder.php | 52 +- app/Models/PurchaseOrderItem.php | 30 +- app/Models/Quiz.php | 22 +- app/Models/Refund.php | 61 +- app/Models/Reimbursement.php | 53 +- app/Models/ReimbursementBatch.php | 35 +- app/Models/ReimbursementBatchAdminFile.php | 23 +- app/Models/ReimbursementBatchItem.php | 35 +- app/Models/ReportCardAcknowledgement.php | 34 +- app/Models/Role.php | 88 +- app/Models/RoleNavItem.php | 21 +- app/Models/RolePermission.php | 39 +- app/Models/SchoolClass.php | 10 +- app/Models/SchoolYear.php | 3 - app/Models/ScoreComment.php | 35 +- app/Models/Section.php | 24 +- app/Models/SectionPlacementBatch.php | 3 - app/Models/SemesterScore.php | 73 +- app/Models/SemesterScoreSnapshot.php | 1 + app/Models/Setting.php | 13 +- app/Models/Staff.php | 39 +- app/Models/StaffAttendance.php | 147 +- app/Models/Stats.php | 11 +- app/Models/Student.php | 75 +- app/Models/StudentAllergy.php | 12 +- app/Models/StudentClass.php | 57 +- app/Models/StudentMedicalCondition.php | 12 +- app/Models/StudentPromotionRecord.php | 14 - app/Models/SubjectCurriculum.php | 28 +- app/Models/Supplier.php | 3 +- app/Models/Supply.php | 2 + app/Models/SupplyCategory.php | 3 +- app/Models/SupplyTransaction.php | 2 + app/Models/SupportRequest.php | 3 +- app/Models/Teacher.php | 4 +- app/Models/TeacherClass.php | 74 +- .../TeacherSubmissionNotificationHistory.php | 29 +- app/Models/User.php | 114 +- app/Models/UserNotification.php | 19 +- app/Models/UserRole.php | 35 +- app/Models/WhatsappGroupLink.php | 49 +- app/Models/WhatsappGroupMembership.php | 71 +- app/Models/WhatsappInviteLog.php | 48 +- app/Policies/NavItemPolicy.php | 2 +- app/Providers/AppServiceProvider.php | 48 +- app/Providers/EventServiceProvider.php | 60 +- .../CompetitionWinnersAdminService.php | 7 +- .../CompetitionWinnersDomain.php | 2 - .../AdminNotificationSubjectService.php | 15 +- .../AdminNotificationUserService.php | 4 +- .../AdminPrintRecipientService.php | 15 +- .../AdministratorAbsenceService.php | 62 +- .../AdministratorDashboardService.php | 5 +- .../AdministratorEnrollmentEventService.php | 7 +- .../AdministratorEnrollmentQueryService.php | 21 +- .../AdministratorEnrollmentRefundService.php | 6 +- .../AdministratorEnrollmentService.php | 3 +- .../AdministratorEnrollmentStatusService.php | 22 +- .../AdministratorMetricsService.php | 5 +- .../AdministratorNotificationService.php | 5 +- .../AdministratorSharedService.php | 8 +- .../AdministratorTeacherSubmissionService.php | 3 +- .../AdministratorUserSearchService.php | 34 +- .../TeacherSubmissionNotificationService.php | 37 +- .../TeacherSubmissionReportService.php | 15 +- .../TeacherSubmissionSupportService.php | 11 +- .../Trophy/TrophyReportService.php | 4 +- app/Services/ApplicationUrlService.php | 9 +- .../AssignmentDataLoaderService.php | 2 +- .../Assignment/AssignmentSectionService.php | 1 - app/Services/Assignment/AssignmentService.php | 20 +- app/Services/AssignmentService.php | 4 +- .../AttendanceAutoPublishJobService.php | 5 +- .../AttendanceAutoPublishService.php | 5 +- .../Attendance/AttendanceCommentService.php | 4 +- .../AttendanceConsequenceService.php | 33 +- .../AttendanceDailySummaryService.php | 13 +- .../Attendance/AttendancePolicyService.php | 13 +- .../Attendance/AttendanceQueryService.php | 162 +- .../AttendanceRecordSyncService.php | 25 +- app/Services/Attendance/AttendanceService.php | 57 +- .../AttendanceSummaryRebuildService.php | 4 +- .../Attendance/LateSlipLogQueryService.php | 9 +- .../Attendance/SemesterRangeService.php | 6 +- .../Attendance/StaffAttendanceService.php | 134 +- .../StudentAttendanceWriterService.php | 28 +- .../TeacherAttendanceSubmissionService.php | 44 +- .../AttendanceManagementService.php | 122 +- .../AttendanceCaseQueryService.php | 79 +- .../AttendanceCommunicationSupportService.php | 13 +- .../AttendanceEmailComposerService.php | 98 +- .../AttendanceMailerService.php | 2 +- .../AttendanceNotificationLogService.php | 44 +- .../AttendanceNotificationWorkflowService.php | 162 +- .../AttendanceParentLookupService.php | 68 +- .../AttendancePendingViolationService.php | 115 +- .../AttendanceTrackingService.php | 9 +- ...endanceViolationStudentResolverService.php | 103 +- .../DefaultAttendanceMailerService.php | 25 +- .../ViolationRuleEngineService.php | 259 +- app/Services/Auth/ApiLoginSecurityService.php | 4 +- app/Services/Auth/AuthSessionService.php | 6 +- app/Services/Auth/PermissionCheckService.php | 2 +- .../Auth/RegistrationCaptchaService.php | 3 +- .../Auth/RegistrationFormatterService.php | 10 +- app/Services/Auth/RegistrationService.php | 25 +- app/Services/Auth/UserRoleService.php | 8 +- app/Services/BadgeScan/BadgeScanService.php | 3 +- app/Services/Badges/BadgeFormDataService.php | 35 +- app/Services/Badges/BadgePdfService.php | 123 +- app/Services/Badges/BadgePrintLogService.php | 7 +- app/Services/Badges/BadgeService.php | 62 +- .../Badges/BadgeStudentLookupService.php | 13 +- app/Services/Badges/BadgeTextFormatter.php | 13 +- .../Badges/BadgeUserLookupService.php | 51 +- .../Billing/BalanceCalculationService.php | 11 +- app/Services/Billing/BillingTotalsService.php | 2 +- app/Services/Billing/ChargeService.php | 25 +- .../BroadcastEmailComposerService.php | 3 +- .../BroadcastEmailDispatchService.php | 3 +- .../BroadcastEmailImageService.php | 8 +- .../BroadcastEmailRecipientService.php | 1 - .../BroadcastEmailSenderOptionsService.php | 7 +- .../Certificates/CertificateAdminService.php | 2 +- .../Certificates/CertificatePdfService.php | 27 +- ...lassPreparationAdjustmentWriterService.php | 3 +- .../ClassPreparationCalculatorService.php | 3 - .../ClassPreparationContextService.php | 1 - .../ClassPreparationInventoryService.php | 3 +- .../ClassPreparationLogService.php | 1 - .../ClassPreparationPrintService.php | 6 +- .../ClassPreparationRosterService.php | 1 - .../ClassPreparationService.php | 22 +- .../ClassProgressAttachmentService.php | 15 +- .../ClassProgressMetaService.php | 2 +- .../ClassProgressMutationService.php | 15 +- .../ClassProgressQueryService.php | 20 +- .../ClassProgressRuleService.php | 2 - .../ClassSections/ClassAttendanceService.php | 2 +- .../ClassSectionQueryService.php | 14 +- .../CommunicationFamilyService.php | 2 +- .../Communication/CommunicationLogService.php | 2 +- .../CommunicationPreviewService.php | 10 +- .../CommunicationSendService.php | 4 +- .../CommunicationStudentService.php | 4 +- .../CommunicationTemplateService.php | 4 +- .../CompetitionScoresQueryService.php | 4 +- .../CompetitionScoresRosterService.php | 3 +- .../CompetitionScoresSaveService.php | 3 +- .../Dashboard/DashboardRouteService.php | 5 +- .../Discounts/DiscountApplyService.php | 13 +- .../Discounts/DiscountInvoiceService.php | 22 +- .../Discounts/DiscountVoucherService.php | 1 - app/Services/Docs/ApiDocsService.php | 3 +- app/Services/Docs/DocsCatalogService.php | 6 +- app/Services/Docs/OpenApiRouteExporter.php | 18 +- app/Services/Email/EmailAttachmentService.php | 6 +- app/Services/Email/EmailDispatchService.php | 20 +- app/Services/Email/EmailExtractorService.php | 4 +- app/Services/Email/EmailProfileService.php | 2 - .../Email/EmailSenderOptionsService.php | 6 +- app/Services/EmailService.php | 12 +- .../EmergencyContactCrudService.php | 3 +- .../EmergencyContactDirectoryService.php | 11 +- .../Events/EventChargeQueryService.php | 9 +- app/Services/Events/EventChargeService.php | 7 +- app/Services/Events/EventListService.php | 12 +- .../Events/EventManagementService.php | 15 +- .../Events/EventStudentChargeService.php | 2 +- app/Services/Exams/ExamDraftAdminService.php | 27 +- app/Services/Exams/ExamDraftConfigService.php | 4 - app/Services/Exams/ExamDraftFileService.php | 39 +- .../Exams/ExamDraftTeacherService.php | 10 +- .../Expenses/ExpenseReceiptService.php | 5 +- app/Services/Expenses/ExpenseStaffService.php | 7 +- app/Services/Expenses/ExpenseWriteService.php | 1 - .../ExtraChargesChargeService.php | 29 +- .../ExtraChargesInvoiceService.php | 6 +- .../ExtraCharges/ExtraChargesMetaService.php | 6 +- .../ExtraChargesParentService.php | 9 +- .../Families/FamilyMutationService.php | 21 +- .../Families/FamilyNotificationService.php | 4 +- app/Services/Families/FamilyQueryService.php | 23 +- app/Services/FeeCalculationService.php | 4 +- app/Services/Fees/FeeGradeService.php | 1 - .../Fees/FeeRefundCalculatorService.php | 21 +- app/Services/Fees/FeeRefundDetailService.php | 23 +- app/Services/Fees/FeeStudentFeeService.php | 12 +- .../Fees/TuitionCalculationService.php | 10 +- .../Files/ExamDraftDownloadNameService.php | 7 +- app/Services/Files/FileServeService.php | 14 +- .../Finance/FinanceNotificationLogService.php | 21 +- .../Finance/FinancialChartService.php | 7 +- .../Finance/FinancialPaymentService.php | 8 +- .../Finance/FinancialPdfReportService.php | 14 +- .../Finance/FinancialReportService.php | 9 +- .../Finance/FinancialSchoolYearService.php | 2 +- .../Finance/FinancialSummaryService.php | 88 +- .../Finance/FinancialUnpaidParentsService.php | 20 +- .../Finance/InstallmentPlanService.php | 33 +- .../Finance/ParentPaymentFollowUpService.php | 140 +- .../PriorYearBalanceCarryforwardService.php | 76 +- .../StakeholderFinancialAnalysisService.php | 83 +- .../Frontend/ContactSubmissionService.php | 15 +- .../LandingPageParentDashboardService.php | 3 +- .../Frontend/LandingPageRoleService.php | 4 +- app/Services/Frontend/LandingPageService.php | 7 +- .../LandingPageTeacherSummaryService.php | 60 +- app/Services/Frontend/ProfileIconService.php | 4 +- app/Services/Frontend/StaticPageService.php | 4 +- .../Grading/BelowSixtyEmailService.php | 14 +- .../Grading/GradingBelowSixtyService.php | 118 +- app/Services/Grading/GradingLockService.php | 16 +- .../Grading/GradingOverviewService.php | 19 +- .../Grading/GradingPlacementService.php | 23 +- .../Grading/GradingRefreshService.php | 6 +- app/Services/Grading/GradingScoreService.php | 32 +- .../HomeworkTrackingCalendarService.php | 4 +- .../Grading/HomeworkTrackingService.php | 26 +- .../Grading/Policy/GradingPolicyResolver.php | 6 +- .../StrongCategoryAverageCalculator.php | 3 - .../GradebookFinalizationValidator.php | 2 +- .../Validation/ScoreValueValidator.php | 3 +- .../Incidents/CurrentIncidentService.php | 20 +- .../Incidents/IncidentAnalysisService.php | 9 +- .../Incidents/IncidentHistoryService.php | 8 +- .../Incidents/IncidentLookupService.php | 7 +- .../Inventory/InventoryCategoryService.php | 16 +- .../Inventory/InventoryItemService.php | 39 +- .../Inventory/InventoryMovementService.php | 37 +- .../Inventory/InventorySummaryService.php | 14 +- .../InventoryTeacherDistributionService.php | 61 +- app/Services/Inventory/SupplierService.php | 19 +- .../Inventory/SupplyCategoryService.php | 13 +- .../Invoices/InvoiceConfigService.php | 3 +- .../Invoices/InvoiceGenerationService.php | 21 +- app/Services/Invoices/InvoiceGradeService.php | 10 +- .../Invoices/InvoiceManagementService.php | 17 +- .../Invoices/InvoicePaymentService.php | 12 +- app/Services/Invoices/InvoicePdfService.php | 55 +- app/Services/Invoices/InvoiceService.php | 3 +- .../Invoices/InvoiceTuitionService.php | 6 +- .../Messaging/MessageCommandService.php | 17 +- .../Messaging/MessageQueryService.php | 11 +- .../Messaging/MessageRecipientService.php | 4 +- app/Services/Navigation/NavBuilderService.php | 16 +- app/Services/Navigation/NavbarService.php | 4 +- .../NotificationManagementService.php | 4 +- .../Notifications/NotificationReadService.php | 2 +- .../NotificationRecipientService.php | 1 - .../Notifications/NotificationSendService.php | 7 +- .../NotificationUserListService.php | 4 +- .../AuthorizedUsersManagementService.php | 3 +- .../ParentAttendanceReportCalendarService.php | 14 +- .../Parents/ParentAttendanceReportService.php | 65 +- .../Parents/ParentAttendanceService.php | 4 +- .../Parents/ParentEmergencyContactService.php | 3 +- .../Parents/ParentEnrollmentService.php | 14 +- .../ParentEventParticipationService.php | 8 +- app/Services/Parents/ParentProfileService.php | 1 - .../Parents/ParentProgressQueryService.php | 11 +- .../Parents/ParentRegistrationService.php | 10 +- .../Parents/ParentReportCardService.php | 9 +- .../Parents/PrimaryParentUserResolver.php | 8 +- .../PaymentEnrollmentEventService.php | 9 +- .../Payments/PaymentEventChargesService.php | 8 +- .../Payments/PaymentManualService.php | 67 +- .../Payments/PaymentMissedCheckService.php | 9 +- .../PaymentNotificationDispatchService.php | 2 +- .../Payments/PaymentNotificationService.php | 34 +- .../PaymentTestNotificationService.php | 24 +- .../Payments/PaymentTransactionService.php | 2 +- .../Payments/PaypalPaymentService.php | 44 +- .../Payments/PaypalPaymentSyncService.php | 27 +- .../Payments/PaypalTransactionsService.php | 20 +- app/Services/Policy/PolicyContentService.php | 7 +- .../Preferences/PreferencesCommandService.php | 5 +- .../Preferences/PreferencesOptionsService.php | 6 +- .../Preferences/PreferencesQueryService.php | 14 +- .../PrintRequestsPortalService.php | 7 +- .../Promotions/LevelProgressionService.php | 27 +- .../BalancedSectionPlacementService.php | 3 - .../Placement/PlacementPoolBuilder.php | 18 +- .../PromotionSectionCapacityService.php | 3 +- .../SectionPlacementPreviewService.php | 17 +- .../PromotionEligibilityService.php | 27 +- .../Promotions/PromotionEnrollmentService.php | 31 +- .../Promotions/PromotionQueryService.php | 34 +- .../Promotions/PromotionReminderService.php | 18 +- .../Promotions/PromotionStatusService.php | 13 +- .../PublicWinnersPortalService.php | 6 +- .../PurchaseOrderCreateService.php | 2 +- .../PurchaseOrderQueryService.php | 2 +- .../PurchaseOrderReceiveService.php | 10 +- .../PurchaseOrderStatusService.php | 2 +- .../Refunds/RefundDecisionService.php | 6 +- .../RefundInvoiceAdjustmentService.php | 6 +- .../Refunds/RefundOverpaymentService.php | 23 +- app/Services/Refunds/RefundPayoutService.php | 5 +- app/Services/Refunds/RefundPolicyService.php | 13 +- app/Services/Refunds/RefundQueryService.php | 18 +- app/Services/Refunds/RefundRequestService.php | 12 +- .../ReimbursementBatchAssignmentService.php | 16 +- .../ReimbursementBatchService.php | 16 +- .../ReimbursementDonationService.php | 6 +- .../ReimbursementEmailService.php | 90 +- .../ReimbursementExportService.php | 43 +- .../ReimbursementFileService.php | 27 +- .../ReimbursementQueryService.php | 61 +- .../ReimbursementRecipientService.php | 14 +- .../Reports/ReportCards/ReportCardService.php | 152 +- .../Reports/SlipPrinterConfigService.php | 3 +- .../Reports/SlipPrinterFormatterService.php | 22 +- .../Reports/SlipPrinterPdfService.php | 8 +- app/Services/Reports/SlipPrinterService.php | 8 +- .../Reports/Stickers/StickerPresetService.php | 3 +- .../Reports/Stickers/StickerPrintService.php | 19 +- .../Reports/Stickers/StickerQueryService.php | 7 +- app/Services/Roles/PermissionCrudService.php | 7 +- app/Services/Roles/RoleAssignmentService.php | 9 +- app/Services/Roles/RoleCrudService.php | 13 +- app/Services/Roles/RoleDashboardService.php | 2 +- app/Services/Roles/RolePermissionService.php | 14 +- app/Services/Roles/RoleQueryService.php | 24 +- app/Services/Roles/RoleStaffService.php | 16 +- app/Services/Roles/RoleSwitchService.php | 5 +- app/Services/School/AccountEventService.php | 44 +- .../School/EnrollmentEventService.php | 42 +- app/Services/School/PaymentEventService.php | 35 +- app/Services/SchoolIdService.php | 6 +- .../SchoolIds/SchoolIdAssignmentService.php | 4 +- .../SchoolIds/SchoolIdGenerationService.php | 4 +- .../SchoolYears/SchoolYearClosureService.php | 52 +- .../SchoolYears/SchoolYearContextService.php | 12 +- .../SchoolYears/SchoolYearResolver.php | 2 +- .../SchoolYears/SchoolYearWriteGuard.php | 2 +- app/Services/Scores/AttendanceCalculator.php | 24 +- app/Services/Scores/ExamScoreService.php | 18 +- app/Services/Scores/HomeworkCalculator.php | 5 +- app/Services/Scores/HomeworkScoreService.php | 28 +- .../Scores/ParticipationScoreService.php | 18 +- app/Services/Scores/ProjectCalculator.php | 5 +- app/Services/Scores/ProjectScoreService.php | 25 +- app/Services/Scores/QuizCalculator.php | 2 +- app/Services/Scores/QuizScoreService.php | 26 +- app/Services/Scores/ScoreCommentService.php | 37 +- app/Services/Scores/ScoreDashboardService.php | 17 +- .../Scores/ScorePredictorDataService.php | 4 +- .../Scores/ScorePredictorRiskService.php | 25 +- app/Services/Scores/ScorePredictorService.php | 3 +- app/Services/Scores/ScoreTermService.php | 1 - app/Services/Scores/SemesterScoreService.php | 46 +- app/Services/Security/IpBanCommandService.php | 8 +- app/Services/Security/IpBanQueryService.php | 5 +- app/Services/SemesterRangeService.php | 15 +- .../Settings/ConfigurationService.php | 4 +- .../SchoolCalendarFormatterService.php | 20 +- .../SchoolCalendarMeetingService.php | 6 +- .../SchoolCalendarMutationService.php | 19 +- .../SchoolCalendarNotificationService.php | 26 +- .../SchoolCalendarQueryService.php | 5 +- app/Services/Settings/SettingsService.php | 2 +- app/Services/Staff/StaffCommandService.php | 14 +- app/Services/Staff/StaffQueryService.php | 13 +- .../Staff/StaffTimeOffLinkService.php | 13 +- .../Students/StudentAssignmentService.php | 21 +- .../StudentAutoDistributionService.php | 6 +- .../Students/StudentDirectoryService.php | 13 +- .../Students/StudentProfileService.php | 14 +- .../Students/StudentScoreCardService.php | 9 +- .../Students/StudentStatusService.php | 10 +- .../Subjects/SubjectCurriculumService.php | 4 +- .../Support/ContactMessageService.php | 12 +- .../Support/SupportRequestService.php | 15 +- .../System/CleanupSchedulerService.php | 2 +- app/Services/System/ConfigUpdateService.php | 24 +- app/Services/System/HealthCheckService.php | 12 +- app/Services/System/TimeService.php | 6 +- .../Teachers/TeacherAbsenceService.php | 63 +- .../Teachers/TeacherAssignmentService.php | 16 +- .../Teachers/TeacherDashboardService.php | 20 +- app/Services/Ui/UiStyleService.php | 10 +- .../Users/DeleteUnverifiedUserService.php | 8 +- .../Users/InactiveUserCleanupService.php | 1 - app/Services/Users/UserEventService.php | 11 +- app/Services/Users/UserListService.php | 8 +- app/Services/Users/UserManagementService.php | 22 +- .../Whatsapp/WhatsappContactService.php | 40 +- .../Whatsapp/WhatsappContextService.php | 4 +- .../Whatsapp/WhatsappInviteBundleService.php | 47 +- .../Whatsapp/WhatsappInviteEmailService.php | 59 +- .../WhatsappInviteNotificationService.php | 23 +- .../Whatsapp/WhatsappInviteService.php | 13 +- app/Services/Whatsapp/WhatsappLinkService.php | 23 +- .../Whatsapp/WhatsappMembershipService.php | 7 +- app/Support/MailHtml.php | 10 +- app/Support/SessionTimeoutConfig.php | 2 - app/ThirdParty/fpdf/font/courier.php | 9 +- app/ThirdParty/fpdf/font/courierb.php | 9 +- app/ThirdParty/fpdf/font/courierbi.php | 9 +- app/ThirdParty/fpdf/font/courieri.php | 9 +- app/ThirdParty/fpdf/font/helvetica.php | 30 +- app/ThirdParty/fpdf/font/helveticab.php | 30 +- app/ThirdParty/fpdf/font/helveticabi.php | 30 +- app/ThirdParty/fpdf/font/helveticai.php | 30 +- app/ThirdParty/fpdf/font/symbol.php | 30 +- app/ThirdParty/fpdf/font/times.php | 30 +- app/ThirdParty/fpdf/font/timesb.php | 30 +- app/ThirdParty/fpdf/font/timesbi.php | 30 +- app/ThirdParty/fpdf/font/timesi.php | 30 +- app/ThirdParty/fpdf/font/zapfdingbats.php | 30 +- app/ThirdParty/fpdf/fpdf.php | 3869 ++++++++--------- bootstrap/app.php | 62 +- bootstrap/providers.php | 7 +- config/auth.php | 4 +- config/jwt.php | 7 +- config/sanctum.php | 9 +- database/factories/ClassSectionFactory.php | 4 +- database/factories/StudentFactory.php | 6 +- database/factories/UserFactory.php | 4 +- .../0001_01_01_000000_create_users_table.php | 1 + .../0001_01_01_000001_create_cache_table.php | 1 + .../0001_01_01_000002_create_jobs_table.php | 2 + .../2026_02_23_204001_create_users_table.php | 7 +- ...026_02_23_204002_create_students_table.php | 10 +- ...026_02_23_204030_create_expenses_table.php | 10 +- ...3_204035_create_current_incident_table.php | 7 +- ...026_02_23_204036_create_incident_table.php | 10 +- ...2_23_204037_create_grading_locks_table.php | 10 +- ...026_02_23_204038_create_homework_table.php | 8 +- ...4039_create_inventory_categories_table.php | 10 +- ...23_204040_create_inventory_items_table.php | 12 +- ...04041_create_inventory_movements_table.php | 12 +- ...2_23_204042_create_invoice_event_table.php | 10 +- ...026_02_23_204043_create_invoices_table.php | 10 +- ...044_create_invoice_students_list_table.php | 10 +- ..._02_23_204045_create_ip_attempts_table.php | 10 +- ..._23_204046_create_late_slip_logs_table.php | 8 +- ..._23_204047_create_login_activity_table.php | 10 +- ...23_204048_create_manual_payments_table.php | 10 +- ...026_02_23_204049_create_messages_table.php | 10 +- ...02_23_204050_create_midterm_exam_table.php | 8 +- ...1_create_missing_score_overrides_table.php | 10 +- ...26_02_23_204052_create_nav_items_table.php | 10 +- ...2_23_204053_create_notifications_table.php | 10 +- ...create_parent_attendance_reports_table.php | 10 +- ..._create_parent_meeting_schedules_table.php | 10 +- ...2026_02_23_204056_create_parents_table.php | 10 +- ...4057_create_parent_notifications_table.php | 10 +- ...2_23_204058_create_participation_table.php | 10 +- ...23_204059_create_password_resets_table.php | 11 +- ...0_create_password_reset_requests_table.php | 10 +- ...100_create_reimbursement_batches_table.php | 12 +- ...23_204101_create_paypal_payments_table.php | 10 +- ..._23_204101_create_reimbursements_table.php | 10 +- ...2_23_204102_create_payment_error_table.php | 10 +- ...026_02_23_204103_create_payments_table.php | 10 +- ...create_payment_notification_logs_table.php | 10 +- ...4105_create_payment_transactions_table.php | 10 +- ...04106_create_paypal_transactions_table.php | 11 +- ..._02_23_204107_create_permissions_table.php | 10 +- ..._204108_create_placement_batches_table.php | 10 +- ...3_204109_create_placement_levels_table.php | 12 +- ...3_204110_create_placement_scores_table.php | 10 +- ...3_204111_create_user_preferences_table.php | 10 +- ..._23_204112_create_print_requests_table.php | 13 +- ...2026_02_23_204113_create_project_table.php | 10 +- ...23_204114_create_promotion_queue_table.php | 10 +- .../2026_02_23_204117_create_quiz_table.php | 10 +- ...2026_02_23_204118_create_refunds_table.php | 10 +- ..._reimbursement_batch_admin_files_table.php | 10 +- .../2026_02_23_204123_create_roles_table.php | 10 +- ..._23_204124_create_role_nav_items_table.php | 10 +- ...3_204125_create_role_permissions_table.php | 10 +- ..._23_204126_create_score_comments_table.php | 10 +- ...026_02_23_204127_create_sections_table.php | 10 +- ...23_204128_create_semester_scores_table.php | 10 +- ...026_02_23_204129_create_settings_table.php | 10 +- ...3_204130_create_staff_attendance_table.php | 12 +- .../2026_02_23_204131_create_staff_table.php | 10 +- ..._204133_create_student_allergies_table.php | 12 +- ...2_23_204134_create_student_class_table.php | 10 +- ...reate_student_medical_conditions_table.php | 12 +- ..._create_subject_curriculum_items_table.php | 10 +- ...2_23_204138_create_teacher_class_table.php | 10 +- ..._submission_notification_history_table.php | 10 +- ...204142_create_user_notifications_table.php | 10 +- ...6_02_23_204143_create_user_roles_table.php | 10 +- ...4144_create_whatsapp_group_links_table.php | 10 +- ...reate_whatsapp_group_memberships_table.php | 8 +- ...4146_create_whatsapp_invites_log_table.php | 10 +- ...50_create_class_progress_reports_table.php | 10 +- ...ate_report_card_acknowledgements_table.php | 7 +- ...reate_class_progress_attachments_table.php | 12 +- ...create_reimbursement_batch_items_table.php | 12 +- ...900001_create_additional_charges_table.php | 10 +- ...eate_admin_notification_subjects_table.php | 10 +- ...eate_attendance_comment_template_table.php | 10 +- ...23_900004_create_attendance_data_table.php | 10 +- ..._23_900005_create_attendance_day_table.php | 10 +- ..._900006_create_attendance_record_table.php | 10 +- ...00007_create_attendance_tracking_table.php | 12 +- ...3_900008_create_authorized_users_table.php | 10 +- ...3_900009_create_badge_print_logs_table.php | 10 +- ...23_900010_create_calendar_events_table.php | 11 +- ...026_02_23_900011_create_chapters_table.php | 10 +- ...02_23_900012_create_classSection_table.php | 10 +- ...13_create_class_prep_adjustments_table.php | 10 +- ...014_create_class_preparation_log_table.php | 10 +- ...2026_02_23_900017_create_classes_table.php | 11 +- ...create_competition_class_winners_table.php | 10 +- ...900019_create_competition_scores_table.php | 10 +- ...00020_create_competition_winners_table.php | 10 +- ...02_23_900021_create_competitions_table.php | 10 +- ...2_23_900022_create_configuration_table.php | 10 +- ...26_02_23_900023_create_contactus_table.php | 10 +- ...02_23_900024_create_current_flag_table.php | 10 +- ...23_900025_create_discount_usages_table.php | 10 +- ..._900026_create_discount_vouchers_table.php | 10 +- ...reate_early_dismissal_signatures_table.php | 10 +- ...23_900028_create_email_templates_table.php | 10 +- ...900029_create_emergency_contacts_table.php | 10 +- ..._02_23_900030_create_enrollments_table.php | 10 +- ...2_23_900031_create_event_charges_table.php | 8 +- .../2026_02_23_900032_create_events_table.php | 10 +- ..._02_23_900033_create_exam_drafts_table.php | 12 +- ..._create_examquestiondistribution_table.php | 10 +- ...2_23_900035_create_examquestions_table.php | 10 +- .../2026_02_23_900036_create_exams_table.php | 10 +- ...026_02_23_900038_create_families_table.php | 11 +- ..._900039_create_family_comm_prefs_table.php | 12 +- ...3_900040_create_family_guardians_table.php | 12 +- ...23_900041_create_family_students_table.php | 12 +- ...6_02_23_900042_create_final_exam_table.php | 10 +- ..._02_23_900043_create_final_score_table.php | 10 +- ...00044_create_longanswerquestions_table.php | 10 +- ...6_create_notification_recipients_table.php | 10 +- ..._02_23_900047_create_preferences_table.php | 10 +- ...02_23_900048_create_qcmquestions_table.php | 10 +- ...26_02_23_900049_create_questions_table.php | 10 +- ...900050_create_questionstruefalse_table.php | 10 +- ...2_23_900051_create_questiontypes_table.php | 10 +- ...026_02_23_900052_create_scan_log_table.php | 10 +- ...0053_create_shortanswerquestions_table.php | 10 +- ...3_900054_create_support_requests_table.php | 10 +- ...5_create_teacher_attendance_data_table.php | 10 +- ...900056_create_communication_logs_table.php | 8 +- ...9_070060_add_fields_to_suppliers_table.php | 8 +- ...20000_create_certificate_records_table.php | 7 +- .../2026_06_04_120010_create_flag_table.php | 7 +- ...000_create_below_sixty_decisions_table.php | 7 +- ..._130010_create_student_decisions_table.php | 7 +- ...lifecycle_and_section_placement_tables.php | 12 +- ...00000_add_badge_scanning_list_nav_item.php | 8 +- ..._strong_grading_backward_compatibility.php | 22 +- ...04_230000_add_finance_lifecycle_tables.php | 18 +- ...0000_create_school_year_closure_tables.php | 13 +- ...5_000000_sort_nav_items_alphabetically.php | 2 +- .../2026_06_09_000000_create_stats_table.php | 29 + docs/alrahma_end_to_end_use_case_test_plan.md | 18 + gitlab-ci.yml | 33 +- phpunit.xml | 10 +- routes/api.php | 213 +- tests/Concerns/AssertsE2EApiResponses.php | 6 +- tests/Concerns/CreatesApiTestUsers.php | 2 +- .../Concerns/SeedsAdministratorApiConfig.php | 2 +- tests/Concerns/SeedsE2ETestFixtures.php | 16 +- .../ApiAuthenticationAndAuthorizationTest.php | 5 +- .../Feature/Api/ApiPreferencesFeatureTest.php | 1 + tests/Feature/Api/ApiPublicEndpointsTest.php | 2 +- .../Api/ApiRolePermissionFeatureTest.php | 2 + tests/Feature/Api/ApiRouteContractTest.php | 10 +- .../Api/ApiUseCaseCoverageMatrixTest.php | 10 +- .../Api/ApiUserManagementFeatureTest.php | 1 + .../AdministratorAbsenceControllerTest.php | 2 +- .../AdministratorEnrollmentControllerTest.php | 2 +- ...stratorEnrollmentUpdateStatusesApiTest.php | 3 +- ...dministratorNotificationControllerTest.php | 2 +- ...stratorTeacherSubmissionControllerTest.php | 2 +- ...istratorTeacherSubmissionReportApiTest.php | 2 +- .../EmergencyContactControllerTest.php | 10 +- .../AssignmentApiControllerTest.php | 8 +- tests/Feature/Api/V1/AssignmentApiTest.php | 98 +- .../Attendance/LateSlipLogsControllerTest.php | 2 +- .../V1/AttendanceCommentTemplateApiTest.php | 12 +- .../AttendanceTrackingControllerTest.php | 3 +- .../Api/V1/Auth/IpBanControllerTest.php | 2 +- tests/Feature/Api/V1/BadgeControllerTest.php | 2 +- .../BroadcastEmailControllerTest.php | 7 +- .../ClassProgressControllerTest.php | 10 +- .../V1/Classes/ClassSectionControllerTest.php | 2 +- .../CommunicationControllerTest.php | 4 +- .../V1/Family/FamilyAdminControllerTest.php | 8 +- .../Api/V1/Family/FamilyControllerTest.php | 6 +- .../V1/Finance/EventChargeControllerTest.php | 12 +- .../V1/Frontend/FrontendControllerTest.php | 2 +- .../V1/Frontend/InfoIconControllerTest.php | 1 + .../V1/Frontend/LandingPageControllerTest.php | 2 +- .../Api/V1/Frontend/PageControllerTest.php | 4 +- ...demicAttendanceFullSurfaceContractTest.php | 76 +- .../ApiAccountStatusLifecycleContractTest.php | 2 +- ...AdminOperationsFullSurfaceContractTest.php | 20 +- ...achmentUploadContentSafetyContractTest.php | 2 +- ...AdministrativeTraceabilityContractTest.php | 4 +- ...thenticationLifecycleDepthContractTest.php | 28 +- ...orizationCacheInvalidationContractTest.php | 4 +- .../ApiBatch11RouteRegressionNetTest.php | 4 +- ...Batch12AttachmentLifecycleContractTest.php | 3 +- ...PromotionRollbackIntegrityContractTest.php | 8 +- ...merationAndIdentityPrivacyContractTest.php | 10 +- ...DelegationApprovalWorkflowContractTest.php | 8 +- ...14ApiConsumerContractCompatibilityTest.php | 16 +- ...endanceDeviceAndKioskAbuseContractTest.php | 8 +- ...AuditTrailTamperResistanceContractTest.php | 8 +- ...h14BulkAssignmentCollisionContractTest.php | 12 +- ...14CrossModuleInvariantRiskRegisterTest.php | 6 +- ...4DataLifecycleArchivePurgeContractTest.php | 11 +- ...conciliationAndRefundAbuseContractTest.php | 14 +- ...ificationTemplateInjectionContractTest.php | 16 +- ...atch14PrintExportTamperingContractTest.php | 8 +- .../ApiBatch14RegressionMegaSweepTest.php | 6 +- ...lationshipOwnershipMatrixExpansionTest.php | 12 +- ...4SessionCookieCsrfBoundaryContractTest.php | 4 +- ...h14StoragePathAndSignedUrlContractTest.php | 10 +- ...personationSessionBoundaryContractTest.php | 2 + ...TokenRotationAndRevocationContractTest.php | 2 + ...kgroundCommandAndSchedulerContractTest.php | 2 + ...rivacyAndDataSubjectRightsContractTest.php | 2 + ...ossSchoolIdentityCollisionContractTest.php | 2 + ...aResidencyBackupAndRestoreContractTest.php | 2 + ...AndNotificationConsistencyContractTest.php | 2 + ...reFlagExperimentAndRolloutContractTest.php | 2 + ...questAuthorizationCoverageContractTest.php | 2 + ...rchAndDirectoryEnumerationContractTest.php | 2 + ...ontentDirectionAndEncodingContractTest.php | 2 + ...gAndSparseFieldsetSecurityContractTest.php | 2 + ...15RateLimitAndAbusePatternContractTest.php | 4 +- .../ApiBatch15RegressionUltraSweepTest.php | 2 + ...illdownAndAggregatePrivacyContractTest.php | 2 + ...15RouteParameterPoisoningExpansionTest.php | 4 +- ...ntSafetyIncidentEscalationContractTest.php | 2 + ...cPrerequisiteAndDependencyContractTest.php | 1 + ...ContractDiffAndCriticalKeyRegisterTest.php | 1 + ...ch17AttendanceTamperWindowContractTest.php | 1 + ...nicationRecipientExpansionContractTest.php | 1 + ...ineageAndSourceAttributionContractTest.php | 1 + ...7ExportColumnLevelSecurityContractTest.php | 1 + ...alIdAndNaturalKeyCollisionContractTest.php | 1 + ...alPeriodCloseAndAdjustmentContractTest.php | 1 + ...tch17InventoryAssetCustodyContractTest.php | 1 + ...iBatch17MultiGuardBoundaryContractTest.php | 1 + ...ailureErrorDetailRedactionContractTest.php | 1 + ...rResourceRateLimitIdentityContractTest.php | 1 + .../ApiBatch17RegressionOmegaSweepTest.php | 1 + ...RankingAndPermissionFilterContractTest.php | 1 + ...7StudentIdentityMergeSplitContractTest.php | 1 + ...h17ZeroTrustInternalHeaderContractTest.php | 1 + ...eAccountAndMachineIdentityContractTest.php | 1 + ...icalIdentifierImmutabilityContractTest.php | 1 + ...aitlistAndScheduleConflictContractTest.php | 1 + ...AndCommunicationComplianceContractTest.php | 1 + ...ossModuleBusinessInvariantRegisterTest.php | 1 + ...rtWatermarkAndAuditabilityContractTest.php | 1 + ...itlementAndLicenseBoundaryContractTest.php | 1 + ...FileVirusScanAndQuarantineContractTest.php | 1 + ...18FinanceChargebackDisputeContractTest.php | 1 + ...edRecordAndCascadeBoundaryContractTest.php | 1 + ...eBoundaryAfterRoleMutationContractTest.php | 1 + .../ApiBatch18RegressionFinalitySweepTest.php | 1 + ...throughAndRowLevelSecurityContractTest.php | 1 + ...lAndSafetyDataMinimizationContractTest.php | 1 + ...ralAuditAndTimezoneForgeryContractTest.php | 1 + ...rsonApprovalAndSegregationContractTest.php | 1 + ...okOrderingAndOutOfSequenceContractTest.php | 1 + ...h19AggregateDashboardScopeContractTest.php | 1 + ...tch19AppendOnlyAuditLedgerContractTest.php | 1 + ...nceExcuseDocumentLifecycleContractTest.php | 1 + ...ributeBasedAccessConditionContractTest.php | 1 + ...ch19BackupRestoreIsolationContractTest.php | 1 + ...ansferTranscriptContinuityContractTest.php | 1 + ...ounceAndSuppressionWebhookContractTest.php | 1 + ...rictionPickupAuthorizationContractTest.php | 1 + ...estedRelationshipRedactionContractTest.php | 1 + ...ationalAndPrivacyInvariantRegisterTest.php | 1 + ...aymentAllocationAndBalanceContractTest.php | 1 + ...ethodAndSettlementBoundaryContractTest.php | 1 + ...piBatch19RegressionContinuitySweepTest.php | 1 + ...h19ReportCacheInvalidationContractTest.php | 1 + ...edDeletedUserTokenBoundaryContractTest.php | 1 + ...eacherSubstitutionCoverageContractTest.php | 1 + ...aryUrlExpirationRevocationContractTest.php | 1 + ...dPartySyncCanonicalizationContractTest.php | 1 + ...0AdminAuditExportRedactionContractTest.php | 1 + ...eprecationAndCompatibilityContractTest.php | 1 + ...anceGeofenceAndDeviceTrustContractTest.php | 1 + ...awerManualPaymentIntegrityContractTest.php | 1 + ...CapacityLotteryAndWaitlistContractTest.php | 1 + ...20ContinuityComplianceRiskRegisterTest.php | 1 + ...taWarehouseAnalyticsExportContractTest.php | 1 + ...0EmergencyClosureBroadcastContractTest.php | 1 + ...0GradebookLockAndAmendmentContractTest.php | 1 + ...dRetentionAndPurgeConflictContractTest.php | 1 + ...ngualContentAndTranslationContractTest.php | 1 + ...ficationDeadLetterAndRetryContractTest.php | 1 + ...entDisputeAndCustodyReviewContractTest.php | 1 + ...ingAndTaxDocumentIntegrityContractTest.php | 1 + ...egressionContinuityComplianceSweepTest.php | 3 +- ...rshipRenewalAndEligibilityContractTest.php | 1 + ...SiblingFamilyDiscountAbuseContractTest.php | 1 + ...icMonitoringAndHealthProbeContractTest.php | 1 + ...portationPickupRouteSafetyContractTest.php | 1 + ...tch20WebhookSecretRotationContractTest.php | 1 + .../ApiBusinessRuleEdgeCaseContractTest.php | 6 +- ...piCalendarScheduleConflictContractTest.php | 2 +- ...entCompatibilityVersioningContractTest.php | 19 +- ...piConcurrencyAndStaleWriteContractTest.php | 2 +- ...piContractCoverageHeatmapExpansionTest.php | 6 +- .../ApiContractSnapshotSeedTest.php | 3 +- ...ossVersionRouteCompatibilityMatrixTest.php | 8 +- ...piCsvExcelFormulaInjectionContractTest.php | 2 +- ...piDataExportLeastPrivilegeContractTest.php | 4 +- .../ApiDataMinimizationByRoleContractTest.php | 4 +- ...ShapeBackwardCompatibilityContractTest.php | 8 +- ...atabaseTransactionRollbackContractTest.php | 2 +- ...piDeepAuthorizationIsolationMatrixTest.php | 8 +- ...ocumentationAndRouteParityContractTest.php | 9 +- ...leImportExportAndPrintableContractTest.php | 11 +- ...encyAndDuplicateSubmissionContractTest.php | 14 +- ...pPaginationSearchAndFilterContractTest.php | 15 +- ...epResponseShapeAndEnvelopeContractTest.php | 14 +- ...epStateTransitionInvariantContractTest.php | 7 +- .../ApiDeepValidationFailureContractTest.php | 14 +- ...piEmptyDatasetAndNullStateContractTest.php | 2 +- .../ApiEnumAndStateMachineContractTest.php | 6 +- ...ApiEtagConditionalMutationContractTest.php | 2 +- .../ApiFailureModeResilienceExpansionTest.php | 12 +- ...ApiFamilyPortalFullSurfaceContractTest.php | 26 +- ...eFlagAndConfigurationDriftContractTest.php | 2 +- ...yCommunicationsFullSurfaceContractTest.php | 26 +- .../ApiFrontendBackendContractParityTest.php | 14 +- .../ApiFullSurfaceEndToEndContractTest.php | 37 +- .../ApiHtmlJavaScriptEscapingContractTest.php | 2 +- ...tpSemanticsAndMethodSafetyContractTest.php | 8 +- ...iIdempotencyScopeAndReplayContractTest.php | 4 +- .../ApiImportTemplateAndCsvContractTest.php | 6 +- .../ApiMigrationSafeDefaultContractTest.php | 4 +- .../ApiMobileClientToleranceContractTest.php | 4 +- ...ificationMessagingDeliveryContractTest.php | 4 +- ...NullBooleanAndTypeCoercionContractTest.php | 2 +- ...piOpenRedirectAndReturnUrlContractTest.php | 4 +- ...perationalEndpointExposureContractTest.php | 2 +- ...ionalResiliencePayloadSizeContractTest.php | 10 +- ...piOwnerBoundaryAndPrivacyExpansionTest.php | 5 +- ...nationCursorAndOffsetAbuseContractTest.php | 2 +- ...lymorphicOwnershipBoundaryContractTest.php | 12 +- ...PrivacyRetentionAndErasureContractTest.php | 8 +- ...piPublicAndAuthFullSurfaceContractTest.php | 14 +- .../ApiQueryParameterFuzzingContractTest.php | 6 +- ...ApiQueueJobAndAsyncTriggerContractTest.php | 8 +- ...itTokenAndSessionHardeningContractTest.php | 4 +- ...ApiRelationshipCardinalityContractTest.php | 2 +- ...tMathAndFinancialInvariantContractTest.php | 8 +- .../ApiRequestHeaderSpoofingContractTest.php | 4 +- ...RoleWorkflowNegativeMatrixContractTest.php | 2 +- ...ApiRouteNamingVersioningAndHygieneTest.php | 3 +- .../ApiRouteParameterAbuseContractTest.php | 6 +- ...ApiRouteUseCaseCatalogCompletenessTest.php | 8 +- ...chemaKeyStabilityExpansionContractTest.php | 8 +- ...lCalendarAcademicBoundaryExpansionTest.php | 8 +- ...SearchIndexAndAutocompleteContractTest.php | 8 +- ...ngFieldSelectionAndIncludeContractTest.php | 2 +- ...olYearAndSemesterIsolationContractTest.php | 4 +- ...icodeNormalizationAndInputContractTest.php | 6 +- ...FetchSsrfAndCallbackSafetyContractTest.php | 2 +- .../ApiWriteAuditAndTimestampContractTest.php | 2 +- .../Support/FullSurfaceE2EContractCase.php | 19 +- .../V1/Incidents/IncidentControllerTest.php | 2 +- .../InventoryCategoriesControllerTest.php | 6 +- .../InventoryItemsControllerTest.php | 16 +- .../InventoryMovementsControllerTest.php | 4 +- .../V1/Inventory/SuppliersControllerTest.php | 4 +- .../SupplyCategoriesControllerTest.php | 4 +- .../V1/Messaging/MessagesControllerTest.php | 8 +- .../Parents/AuthorizedUsersControllerTest.php | 8 +- .../ParentAttendanceReportControllerTest.php | 3 +- .../PrintRequestsWorkflowTest.php | 4 +- .../ParentPromotionControllerTest.php | 9 +- .../V1/Public/PublicWinnersControllerTest.php | 4 +- .../Api/V1/Reports/FilesControllerTest.php | 8 +- .../V1/Reports/ReportCardsControllerTest.php | 10 +- .../V1/Roles/RolePermissionControllerTest.php | 20 +- .../V1/Roles/RoleSwitcherControllerTest.php | 1 + .../V1/Settings/PreferencesControllerTest.php | 6 +- .../Settings/SchoolCalendarControllerTest.php | 12 +- .../V1/Settings/SettingsControllerTest.php | 3 +- .../Api/V1/Staff/StaffControllerTest.php | 6 +- .../Api/V1/Students/StudentControllerTest.php | 2 +- .../Api/V1/Support/SupportControllerTest.php | 2 +- .../Api/V1/Teachers/TeacherControllerTest.php | 2 +- tests/Feature/Api/V1/Ui/UiControllerTest.php | 2 +- .../Whatsapp/WhatsappInviteControllerTest.php | 3 +- .../Whatsapp/WhatsappLinkControllerTest.php | 6 +- .../ScenarioAFamilyEnrollmentTest.php | 6 +- .../ScenarioBSundaySchoolDayTest.php | 4 +- .../Workflows/ScenarioCAcademicTermTest.php | 4 +- .../Workflows/ScenarioDFamilyBillingTest.php | 4 +- .../V1/Workflows/ScenarioEFinanceEdgeTest.php | 18 +- .../ScenarioFTeacherSubmissionTest.php | 1 + .../V1/Workflows/ScenarioGPrintBadgeTest.php | 4 +- ...cenarioHSecurityUnauthorizedAccessTest.php | 2 +- ...cenarioIPublicAuthAndSystemUseCaseTest.php | 4 +- ...cenarioJCrossModuleApiUseCaseSmokeTest.php | 10 +- ...enarioKParentSelfServiceAndPrivacyTest.php | 10 +- ...ScenarioLTeacherAcademicOperationsTest.php | 14 +- ...tratorEnrollmentAndClassOperationsTest.php | 2 +- ...NCommunicationsAndSupportLifecycleTest.php | 4 +- ...oOInventoryFinanceAndAuditControlsTest.php | 12 +- ...ConfigurationAndCalendarGovernanceTest.php | 18 +- ...choolYearPromotionClosureLifecycleTest.php | 22 +- ...anceOperationsAndExceptionHandlingTest.php | 16 +- ...oringGradingAndReportCardLifecycleTest.php | 27 +- ...rintBadgesAndCertificatesLifecycleTest.php | 12 +- ...ymentRefundAndInstallmentLifecycleTest.php | 30 +- ...entReimbursementAndSupplyLifecycleTest.php | 10 +- ...ntrolRolesNavigationAndPreferencesTest.php | 12 +- ...oskScannerAndVerificationLifecycleTest.php | 8 +- ...AuthorizedUserAndWhatsappLifecycleTest.php | 16 +- ...yAliasesValidationAndCompatibilityTest.php | 36 +- .../StudentEnrollmentWorkflowTest.php | 9 +- tests/Feature/BulkUserRoleCreationTest.php | 2 +- .../RequirePermissionMiddlewareTest.php | 2 +- tests/Feature/Web/SchoolYearAdminPageTest.php | 4 +- tests/Unit/ApiLoginSecurityServiceTest.php | 6 +- tests/Unit/AuthSessionServiceTest.php | 2 +- ...ttendanceCommentTemplateControllerTest.php | 4 +- .../Unit/Grading/ScoreValueValidatorTest.php | 6 +- tests/Unit/Models/AdditionalChargeTest.php | 12 +- .../AttendanceCommentTemplateModelTest.php | 2 +- tests/Unit/Models/AttendanceDataTest.php | 8 +- .../Models/AttendanceEmailTemplateTest.php | 8 +- tests/Unit/Models/AttendanceRecordTest.php | 6 +- tests/Unit/Models/AttendanceTrackingTest.php | 6 +- tests/Unit/Models/AuthorizedUserTest.php | 6 +- tests/Unit/Models/BadgePrintLogTest.php | 6 +- tests/Unit/Models/CalendarTest.php | 6 +- tests/Unit/Models/ClassPrepAdjustmentTest.php | 6 +- tests/Unit/Models/ClassPreparationLogTest.php | 6 +- .../Models/ClassProgressAttachmentTest.php | 6 +- tests/Unit/Models/ClassProgressReportTest.php | 6 +- tests/Unit/Models/ClassSectionTest.php | 6 +- tests/Unit/Models/ClassTest.php | 6 +- tests/Unit/Models/CommunicationLogTest.php | 6 +- .../Models/CompetitionClassWinnerTest.php | 6 +- tests/Unit/Models/CompetitionScoreTest.php | 6 +- tests/Unit/Models/CompetitionTest.php | 8 +- tests/Unit/Models/CompetitionWinnerTest.php | 6 +- tests/Unit/Models/ConfigurationTest.php | 6 +- tests/Unit/Models/ContactUsTest.php | 6 +- tests/Unit/Models/CurrentFlagTest.php | 6 +- tests/Unit/Models/DiscountUsageTest.php | 6 +- tests/Unit/Models/DiscountVoucherTest.php | 6 +- .../Models/EarlyDismissalSignatureTest.php | 6 +- tests/Unit/Models/EmergencyContactTest.php | 6 +- tests/Unit/Models/EnrollmentTest.php | 6 +- tests/Unit/Models/EventChargesTest.php | 6 +- tests/Unit/Models/EventTest.php | 6 +- tests/Unit/Models/ExamDraftTest.php | 6 +- tests/Unit/Models/ExamTest.php | 6 +- tests/Unit/Models/ExpenseTest.php | 6 +- tests/Unit/Models/FamilyCommPrefTest.php | 6 +- tests/Unit/Models/FamilyGuardianTest.php | 6 +- tests/Unit/Models/FamilyStudentTest.php | 6 +- tests/Unit/Models/FamilyTest.php | 6 +- tests/Unit/Models/FinalExamTest.php | 6 +- tests/Unit/Models/FinalScoreTest.php | 6 +- tests/Unit/Models/GradingLockTest.php | 6 +- tests/Unit/Models/HomeworkTest.php | 6 +- tests/Unit/Models/IncidentTest.php | 6 +- tests/Unit/Models/InventoryCategoryTest.php | 6 +- tests/Unit/Models/InventoryItemTest.php | 6 +- tests/Unit/Models/InventoryMovementTest.php | 6 +- tests/Unit/Models/InvoiceEventTest.php | 6 +- tests/Unit/Models/InvoiceStudentListTest.php | 6 +- tests/Unit/Models/InvoiceTest.php | 6 +- tests/Unit/Models/IpAttemptTest.php | 6 +- tests/Unit/Models/LateSlipLogTest.php | 6 +- tests/Unit/Models/LoginActivityTest.php | 6 +- tests/Unit/Models/ManualPaymentTest.php | 6 +- tests/Unit/Models/MessageTest.php | 6 +- tests/Unit/Models/MidtermExamTest.php | 6 +- .../Unit/Models/MissingScoreOverrideTest.php | 6 +- tests/Unit/Models/NavItemTest.php | 8 +- tests/Unit/Models/NotificationTest.php | 8 +- .../Models/ParentAttendanceReportTest.php | 6 +- .../Unit/Models/ParentMeetingScheduleTest.php | 6 +- tests/Unit/Models/ParentNotificationTest.php | 6 +- tests/Unit/Models/ParentTest.php | 6 +- tests/Unit/Models/ParticipationTest.php | 6 +- .../Unit/Models/PasswordResetRequestTest.php | 6 +- tests/Unit/Models/PasswordResetTest.php | 6 +- tests/Unit/Models/PayPalPaymentTest.php | 6 +- tests/Unit/Models/PaymentErrorTest.php | 6 +- .../Models/PaymentNotificationLogTest.php | 6 +- tests/Unit/Models/PaymentTest.php | 6 +- tests/Unit/Models/PaymentTransactionTest.php | 6 +- tests/Unit/Models/PaypalTransactionTest.php | 6 +- tests/Unit/Models/PermissionTest.php | 6 +- tests/Unit/Models/PlacementBatchTest.php | 6 +- tests/Unit/Models/PlacementLevelTest.php | 6 +- tests/Unit/Models/PlacementScoreTest.php | 6 +- tests/Unit/Models/PreferencesTest.php | 6 +- tests/Unit/Models/PrintRequestTest.php | 6 +- tests/Unit/Models/ProjectTest.php | 6 +- tests/Unit/Models/PromotionQueueTest.php | 6 +- tests/Unit/Models/PurchaseOrderItemTest.php | 6 +- tests/Unit/Models/PurchaseOrderTest.php | 8 +- tests/Unit/Models/QuizTest.php | 6 +- tests/Unit/Models/RefundTest.php | 6 +- .../ReimbursementBatchAdminFileTest.php | 6 +- .../Models/ReimbursementBatchItemTest.php | 6 +- tests/Unit/Models/ReimbursementBatchTest.php | 6 +- tests/Unit/Models/ReimbursementTest.php | 6 +- tests/Unit/Models/RoleNavItemTest.php | 6 +- tests/Unit/Models/RolePermissionTest.php | 6 +- tests/Unit/Models/RoleTest.php | 6 +- tests/Unit/Models/ScoreCommentTest.php | 6 +- tests/Unit/Models/SectionTest.php | 6 +- tests/Unit/Models/SemesterScoreTest.php | 6 +- tests/Unit/Models/SettingsTest.php | 6 +- tests/Unit/Models/StaffAttendanceTest.php | 6 +- tests/Unit/Models/StaffTest.php | 6 +- tests/Unit/Models/StatsTest.php | 6 +- tests/Unit/Models/StudentAllergyTest.php | 6 +- tests/Unit/Models/StudentClassTest.php | 6 +- .../Models/StudentMedicalConditionTest.php | 6 +- tests/Unit/Models/StudentTest.php | 6 +- tests/Unit/Models/SubjectCurriculumTest.php | 6 +- tests/Unit/Models/TeacherClassTest.php | 6 +- ...acherSubmissionNotificationHistoryTest.php | 6 +- tests/Unit/Models/TeacherTest.php | 6 +- tests/Unit/Models/UserNotificationTest.php | 6 +- tests/Unit/Models/UserRoleTest.php | 6 +- tests/Unit/Models/UserTest.php | 6 +- tests/Unit/Models/WhatsappGroupLinkTest.php | 6 +- .../Models/WhatsappGroupMembershipTest.php | 6 +- tests/Unit/Models/WhatsappInviteLogTest.php | 6 +- ...reAttendanceCommentTemplateRequestTest.php | 4 +- ...teAttendanceCommentTemplateRequestTest.php | 4 +- .../AdminNotificationSubjectServiceTest.php | 3 +- .../AdminNotificationUserServiceTest.php | 2 +- .../AdminPrintRecipientServiceTest.php | 3 +- .../AdministratorAbsenceServiceTest.php | 16 +- .../AdministratorDashboardServiceTest.php | 6 +- ...dministratorEnrollmentEventServiceTest.php | 2 +- ...dministratorEnrollmentQueryServiceTest.php | 15 +- ...ministratorEnrollmentRefundServiceTest.php | 3 +- .../AdministratorEnrollmentServiceTest.php | 6 +- ...ministratorEnrollmentStatusServiceTest.php | 15 +- .../AdministratorMetricsServiceTest.php | 10 +- .../AdministratorNotificationServiceTest.php | 6 +- .../AdministratorSharedServiceTest.php | 3 +- ...inistratorTeacherSubmissionServiceTest.php | 9 +- .../AdministratorUserSearchServiceTest.php | 2 +- ...acherSubmissionNotificationServiceTest.php | 6 +- .../TeacherSubmissionReportServiceTest.php | 6 +- .../TeacherSubmissionSupportServiceTest.php | 4 +- .../AssignmentContextServiceTest.php | 2 +- .../AssignmentDataLoaderServiceTest.php | 4 +- .../Assignment/AssignmentMetaServiceTest.php | 6 +- .../AssignmentSectionServiceTest.php | 2 +- tests/Unit/Services/AssignmentServiceTest.php | 7 - .../AttendanceAutoPublishJobServiceTest.php | 2 +- .../AttendanceAutoPublishServiceTest.php | 4 +- .../AttendanceCommentServiceTest.php | 4 +- .../AttendanceConsequenceServiceTest.php | 3 +- .../AttendancePolicyServiceTest.php | 8 +- .../Attendance/AttendanceQueryServiceTest.php | 88 +- .../AttendanceRecordSyncServiceTest.php | 5 +- .../AttendanceSemesterRangeServiceTest.php | 4 +- .../Attendance/AttendanceServiceTest.php | 20 +- .../AttendanceSummaryRebuildServiceTest.php | 2 +- .../Attendance/AttendanceTrackingService.php | 299 +- .../Attendance/SemesterRangeServiceTest.php | 8 +- .../Attendance/StaffAttendanceServiceTest.php | 15 +- .../StudentAttendanceWriterServiceTest.php | 6 +- ...TeacherAttendanceSubmissionServiceTest.php | 29 +- .../AttendanceManagementServiceTest.php | 4 +- .../AttendanceCaseQueryServiceTest.php | 15 +- ...endanceCommunicationSupportServiceTest.php | 15 +- .../AttendanceEmailComposerServiceTest.php | 5 +- .../AttendanceNotificationLogServiceTest.php | 3 +- ...endanceNotificationWorkflowServiceTest.php | 30 +- .../AttendanceParentLookupServiceTest.php | 4 +- .../AttendancePendingViolationServiceTest.php | 9 +- .../AttendanceTrackingServiceTest.php | 2 +- ...nceViolationStudentResolverServiceTest.php | 9 +- .../ViolationRuleEngineServiceTest.php | 6 +- .../Auth/PasswordResetCleanupServiceTest.php | 2 +- .../Auth/PermissionCheckServiceTest.php | 2 +- .../Auth/RegistrationCaptchaServiceTest.php | 4 +- .../Auth/RegistrationFormatterServiceTest.php | 4 +- .../Services/Auth/RegistrationServiceTest.php | 12 +- .../Services/Auth/UserRoleServiceTest.php | 2 +- .../Badges/BadgeFormDataServiceTest.php | 6 +- .../Services/Badges/BadgePdfServiceTest.php | 6 +- .../Badges/BadgePrintLogServiceTest.php | 8 +- .../Badges/BadgeTextFormatterTest.php | 6 +- .../Billing/BalanceCalculationServiceTest.php | 8 +- .../Billing/BillingTotalsServiceTest.php | 6 +- .../BroadcastEmailComposerServiceTest.php | 4 +- .../BroadcastEmailRecipientServiceTest.php | 4 +- ...BroadcastEmailSenderOptionsServiceTest.php | 4 +- .../ClassPrep/ClassRosterServiceTest.php | 2 +- .../ClassPrep/StickerCountServiceTest.php | 4 +- .../ClassPreparationAdjustmentServiceTest.php | 2 +- .../ClassPreparationCalculatorServiceTest.php | 4 +- .../ClassPreparationContextServiceTest.php | 2 +- .../ClassPreparationInventoryServiceTest.php | 2 +- .../ClassPreparationLogServiceTest.php | 5 +- .../ClassPreparationRosterServiceTest.php | 4 +- .../ClassProgressAttachmentServiceTest.php | 2 +- .../ClassProgressMetaServiceTest.php | 2 +- .../ClassProgressMutationServiceTest.php | 12 +- .../ClassProgressQueryServiceTest.php | 2 +- .../ClassProgressRuleServiceTest.php | 4 +- .../CommunicationTemplateServiceTest.php | 2 +- .../CompetitionScoresSaveServiceTest.php | 5 +- .../Discounts/DiscountApplyServiceTest.php | 2 +- .../Email/EmailExtractorServiceTest.php | 2 +- .../Email/EmailProfileServiceTest.php | 6 +- .../Events/EventChargeQueryServiceTest.php | 2 +- .../Services/Events/EventListServiceTest.php | 2 +- .../Events/EventStudentChargeServiceTest.php | 2 +- .../Exams/ExamDraftTeacherServiceTest.php | 2 +- .../Expenses/ExpenseReceiptServiceTest.php | 4 +- .../Expenses/ExpenseStaffServiceTest.php | 2 +- .../ExtraChargesMetaServiceTest.php | 4 +- .../Families/FamilyFinanceServiceTest.php | 2 +- .../Families/FamilyMutationServiceTest.php | 8 +- .../Families/FamilyQueryServiceTest.php | 10 +- .../Services/Fees/FeeGradeServiceTest.php | 4 +- .../Fees/FeeRefundCalculatorServiceTest.php | 6 +- .../Fees/FeeRefundDetailServiceTest.php | 2 +- .../Fees/FeeStudentFeeServiceTest.php | 2 +- .../Fees/TuitionCalculationServiceTest.php | 5 +- .../ExamDraftDownloadNameServiceTest.php | 2 +- .../Services/Files/FileServeServiceTest.php | 18 +- .../Finance/FinancialChartServiceTest.php | 2 +- .../Finance/FinancialPaymentServiceTest.php | 2 +- .../Finance/FinancialPdfReportServiceTest.php | 2 +- .../Finance/FinancialReportServiceTest.php | 4 +- .../FinancialSchoolYearServiceTest.php | 2 +- .../Finance/FinancialSummaryServiceTest.php | 2 +- .../FinancialUnpaidParentsServiceTest.php | 2 +- .../Frontend/ContactSubmissionServiceTest.php | 2 +- .../Frontend/FrontendPageServiceTest.php | 2 +- .../Frontend/StaticPageServiceTest.php | 6 +- .../Grading/GradingBelowSixtyServiceTest.php | 2 +- .../Grading/GradingLockServiceTest.php | 4 +- .../Grading/HomeworkTrackingServiceTest.php | 2 +- .../Incidents/IncidentAnalysisServiceTest.php | 2 +- .../Incidents/IncidentHistoryServiceTest.php | 2 +- .../Incidents/IncidentLookupServiceTest.php | 4 +- .../InventoryCategoryServiceTest.php | 4 +- .../Inventory/InventoryItemServiceTest.php | 4 +- .../InventoryMovementServiceTest.php | 2 +- .../Inventory/InventorySummaryServiceTest.php | 2 +- ...nventoryTeacherDistributionServiceTest.php | 8 +- .../Inventory/SupplierServiceTest.php | 4 +- .../Inventory/SupplyCategoryServiceTest.php | 4 +- .../Invoices/InvoiceConfigServiceTest.php | 2 +- .../Invoices/InvoiceGenerationServiceTest.php | 2 +- .../Invoices/InvoiceManagementServiceTest.php | 2 +- .../Invoices/InvoicePaymentServiceTest.php | 2 +- .../Invoices/InvoicePdfServiceTest.php | 2 +- .../Messaging/MessageCommandServiceTest.php | 4 +- .../Messaging/MessageQueryServiceTest.php | 2 +- .../Messaging/MessageRecipientServiceTest.php | 4 +- .../Navigation/NavBuilderServiceTest.php | 6 +- .../Services/Navigation/NavbarServiceTest.php | 2 +- .../NotificationActiveServiceTest.php | 2 +- .../NotificationCleanupServiceTest.php | 2 +- .../NotificationDeletedServiceTest.php | 2 +- .../NotificationDispatchServiceTest.php | 2 +- .../NotificationManagementServiceTest.php | 6 +- .../NotificationReadServiceTest.php | 4 +- .../NotificationRecipientServiceTest.php | 2 +- .../NotificationShowServiceTest.php | 4 +- .../NotificationUserListServiceTest.php | 2 +- .../UserNotificationDispatchServiceTest.php | 4 +- .../ParentAttendanceReportServiceTest.php | 6 +- .../Parents/ParentAttendanceServiceTest.php | 3 +- .../Parents/ParentConfigServiceTest.php | 2 +- .../ParentEmergencyContactServiceTest.php | 2 +- .../Parents/ParentEnrollmentServiceTest.php | 2 +- .../Parents/ParentInvoiceServiceTest.php | 2 +- .../Parents/ParentRegistrationServiceTest.php | 2 +- .../Payments/PaymentBalanceServiceTest.php | 2 +- .../PaymentEnrollmentEventServiceTest.php | 2 +- .../Payments/PaymentLookupServiceTest.php | 2 +- ...PaymentNotificationDispatchServiceTest.php | 2 +- .../Payments/PaymentPlanServiceTest.php | 2 +- .../PaymentTransactionServiceTest.php | 8 +- .../Payments/PaypalPaymentServiceTest.php | 2 +- .../PaypalTransactionsServiceTest.php | 2 +- .../Policy/PolicyContentServiceTest.php | 2 +- .../LevelProgressionServiceTest.php | 8 +- .../PromotionEligibilityServiceTest.php | 10 +- .../PromotionEnrollmentServiceTest.php | 2 +- .../Promotions/PromotionStatusServiceTest.php | 2 +- .../PurchaseOrderCreateServiceTest.php | 2 +- .../PurchaseOrderReceiveServiceTest.php | 2 +- .../PurchaseOrderStatusServiceTest.php | 2 +- .../Refunds/RefundDecisionServiceTest.php | 2 +- .../Refunds/RefundNotificationServiceTest.php | 2 +- .../Refunds/RefundOverpaymentServiceTest.php | 2 +- .../Refunds/RefundPayoutServiceTest.php | 2 +- .../Refunds/RefundPolicyServiceTest.php | 8 +- .../Refunds/RefundQueryServiceTest.php | 2 +- .../Refunds/RefundRequestServiceTest.php | 10 +- .../Refunds/RefundSummaryServiceTest.php | 2 +- ...eimbursementBatchAssignmentServiceTest.php | 2 +- .../ReimbursementBatchServiceTest.php | 2 +- .../ReimbursementDonationServiceTest.php | 2 +- .../ReimbursementRecipientServiceTest.php | 2 +- .../ReportCards/ReportCardServiceTest.php | 10 +- .../SlipPrinterFormatterServiceTest.php | 4 +- .../Stickers/StickerPresetServiceTest.php | 2 +- .../Stickers/StickerPrintServiceTest.php | 4 +- .../Stickers/StickerQueryServiceTest.php | 4 +- .../Roles/PermissionCrudServiceTest.php | 2 +- .../Roles/RoleAssignmentServiceTest.php | 3 +- .../Services/Roles/RoleCrudServiceTest.php | 2 +- .../Roles/RoleDashboardServiceTest.php | 2 +- .../Roles/RolePermissionServiceTest.php | 2 +- .../Services/Roles/RoleQueryServiceTest.php | 4 +- .../Services/Roles/RoleSwitchServiceTest.php | 2 +- .../School/SemesterSelectionServiceTest.php | 4 +- .../SchoolIdGenerationServiceTest.php | 2 +- .../Scores/AttendanceCalculatorTest.php | 2 +- .../Services/Scores/ExamScoreServiceTest.php | 4 +- .../Scores/HomeworkCalculatorTest.php | 2 +- .../Scores/HomeworkScoreServiceTest.php | 4 +- .../Scores/ParticipationScoreServiceTest.php | 4 +- .../Services/Scores/ProjectCalculatorTest.php | 2 +- .../Scores/ProjectScoreServiceTest.php | 6 +- .../Services/Scores/QuizCalculatorTest.php | 2 +- .../Services/Scores/QuizScoreServiceTest.php | 6 +- .../Scores/ScoreCommentServiceTest.php | 4 +- .../Scores/ScoreDashboardServiceTest.php | 4 +- .../Scores/ScorePredictorServiceTest.php | 4 +- .../Services/Scores/ScoreTermServiceTest.php | 4 +- .../Scores/SemesterScoreServiceTest.php | 22 +- .../Services/Security/Pbkdf2HasherTest.php | 2 +- .../Semesters/SemesterConfigServiceTest.php | 2 +- .../Semesters/SemesterRangeServiceTest.php | 6 +- .../Settings/ConfigurationServiceTest.php | 2 +- .../SchoolCalendarContextServiceTest.php | 2 +- .../SchoolCalendarFormatterServiceTest.php | 4 +- .../SchoolCalendarMeetingServiceTest.php | 2 +- .../SchoolCalendarMutationServiceTest.php | 4 +- .../SchoolCalendarQueryServiceTest.php | 4 +- .../Services/Settings/SettingsServiceTest.php | 4 +- .../Staff/StaffCommandServiceTest.php | 4 +- .../Services/Staff/StaffQueryServiceTest.php | 2 +- .../Students/StudentAssignmentServiceTest.php | 4 +- .../Students/StudentProfileServiceTest.php | 2 +- .../Students/StudentScoreCardServiceTest.php | 2 +- .../Subjects/SubjectCurriculumServiceTest.php | 4 +- .../Support/SupportRequestServiceTest.php | 2 +- .../System/CleanupSchedulerServiceTest.php | 6 +- .../System/ConfigUpdateServiceTest.php | 4 +- .../System/GlobalConfigServiceTest.php | 2 +- .../Unit/Services/System/TimeServiceTest.php | 2 +- .../Teachers/TeacherAbsenceServiceTest.php | 14 +- .../Teachers/TeacherAssignmentServiceTest.php | 4 +- .../Teachers/TeacherDashboardServiceTest.php | 2 +- tests/Unit/Services/Ui/UiStyleServiceTest.php | 2 +- .../Users/InactiveUserCleanupServiceTest.php | 2 +- .../Services/Users/UserListServiceTest.php | 1 + .../Whatsapp/WhatsappContactServiceTest.php | 2 +- .../Whatsapp/WhatsappContextServiceTest.php | 4 +- .../WhatsappInviteBundleServiceTest.php | 4 +- .../WhatsappInviteNotificationServiceTest.php | 7 +- .../Whatsapp/WhatsappInviteServiceTest.php | 9 +- .../Whatsapp/WhatsappLinkServiceTest.php | 4 +- .../WhatsappMembershipServiceTest.php | 4 +- 1489 files changed, 10449 insertions(+), 11356 deletions(-) create mode 100644 database/migrations/2026_06_09_000000_create_stats_table.php diff --git a/app/Console/Commands/AttendanceAutoPublishCommand.php b/app/Console/Commands/AttendanceAutoPublishCommand.php index e775c110..fabeff3d 100644 --- a/app/Console/Commands/AttendanceAutoPublishCommand.php +++ b/app/Console/Commands/AttendanceAutoPublishCommand.php @@ -8,7 +8,6 @@ use Illuminate\Console\Command; class AttendanceAutoPublishCommand extends Command { protected $signature = 'attendance:auto-publish'; - protected $description = 'Auto-publish attendance days per "second Sunday backward" rule.'; public function handle(AttendanceAutoPublishJobService $service): int diff --git a/app/Console/Commands/CheckMissedPaymentsCommand.php b/app/Console/Commands/CheckMissedPaymentsCommand.php index ddd883a5..fff09126 100644 --- a/app/Console/Commands/CheckMissedPaymentsCommand.php +++ b/app/Console/Commands/CheckMissedPaymentsCommand.php @@ -8,7 +8,6 @@ use Illuminate\Console\Command; class CheckMissedPaymentsCommand extends Command { protected $signature = 'payments:check-missed'; - protected $description = 'Checks for users who missed payments and sends reminders.'; public function handle(PaymentMissedCheckService $service): int @@ -16,7 +15,6 @@ class CheckMissedPaymentsCommand extends Command $users = $service->findUsersWithMissedPayments(); if (empty($users)) { $this->info('No missed payments found.'); - return self::SUCCESS; } diff --git a/app/Console/Commands/CleanupExpiredNotificationsCommand.php b/app/Console/Commands/CleanupExpiredNotificationsCommand.php index 7e5a8237..94bcabee 100644 --- a/app/Console/Commands/CleanupExpiredNotificationsCommand.php +++ b/app/Console/Commands/CleanupExpiredNotificationsCommand.php @@ -8,7 +8,6 @@ use Illuminate\Console\Command; class CleanupExpiredNotificationsCommand extends Command { protected $signature = 'notifications:cleanup'; - protected $description = 'Deletes expired notifications from the database.'; public function handle(NotificationCleanupService $service): int @@ -17,7 +16,6 @@ class CleanupExpiredNotificationsCommand extends Command if ($count <= 0) { $this->info('No expired notifications found to soft delete.'); - return self::SUCCESS; } diff --git a/app/Console/Commands/CleanupPasswordResetsCommand.php b/app/Console/Commands/CleanupPasswordResetsCommand.php index 136b7845..16d1bdbd 100644 --- a/app/Console/Commands/CleanupPasswordResetsCommand.php +++ b/app/Console/Commands/CleanupPasswordResetsCommand.php @@ -8,7 +8,6 @@ use Illuminate\Console\Command; class CleanupPasswordResetsCommand extends Command { protected $signature = 'cleanup:password-resets {--days=30}'; - protected $description = 'Delete password reset requests older than N days.'; public function handle(PasswordResetCleanupService $service): int diff --git a/app/Console/Commands/ConfigUpdateCommand.php b/app/Console/Commands/ConfigUpdateCommand.php index 5a80c1d9..ac90ecbc 100644 --- a/app/Console/Commands/ConfigUpdateCommand.php +++ b/app/Console/Commands/ConfigUpdateCommand.php @@ -9,7 +9,6 @@ use Illuminate\Console\Command; class ConfigUpdateCommand extends Command { protected $signature = 'config:update {task?} {--task=} {--dry} {--force} {--tz=}'; - protected $description = 'Run a configuration update task (weekly cron).'; public function handle(ConfigUpdateService $service): int @@ -20,20 +19,18 @@ class ConfigUpdateCommand extends Command $tzName = (string) ($this->option('tz') ?: (config('School')->attendance['timezone'] ?? 'UTC')); $tz = new DateTimeZone($tzName); - if ($task === '' || ! in_array($task, $service->availableTasks(), true)) { - $this->error('Invalid or missing --task. Available: '.implode(', ', $service->availableTasks())); - + if ($task === '' || !in_array($task, $service->availableTasks(), true)) { + $this->error('Invalid or missing --task. Available: ' . implode(', ', $service->availableTasks())); return self::FAILURE; } $result = $service->runTask($task, $dry, $force, $tz); - if (! $result['ok']) { + if (!$result['ok']) { $this->error($result['message'] ?? "Task '{$task}' failed."); - return self::FAILURE; } - $this->info("Task '{$task}' finished successfully.".($dry ? ' [DRY RUN]' : '')); + $this->info("Task '{$task}' finished successfully." . ($dry ? ' [DRY RUN]' : '')); return self::SUCCESS; } diff --git a/app/Console/Commands/DeleteInactiveUsersCommand.php b/app/Console/Commands/DeleteInactiveUsersCommand.php index c2a0e199..baa3a450 100644 --- a/app/Console/Commands/DeleteInactiveUsersCommand.php +++ b/app/Console/Commands/DeleteInactiveUsersCommand.php @@ -8,7 +8,6 @@ use Illuminate\Console\Command; class DeleteInactiveUsersCommand extends Command { protected $signature = 'users:delete-inactive-users {--minutes=15}'; - protected $description = 'Delete users that are inactive and created more than N minutes ago.'; public function handle(InactiveUserCleanupService $service): int diff --git a/app/Console/Commands/DeleteUnverifiedUsersCommand.php b/app/Console/Commands/DeleteUnverifiedUsersCommand.php index 1742baf9..bb8a58da 100644 --- a/app/Console/Commands/DeleteUnverifiedUsersCommand.php +++ b/app/Console/Commands/DeleteUnverifiedUsersCommand.php @@ -10,7 +10,6 @@ use Illuminate\Support\Facades\Event; class DeleteUnverifiedUsersCommand extends Command { protected $signature = 'users:delete-unverified {--timeout=86400}'; - protected $description = 'Delete unverified users older than the configured timeout (seconds).'; public function handle(): int diff --git a/app/Console/Commands/RecalculateAttendanceCommand.php b/app/Console/Commands/RecalculateAttendanceCommand.php index 8ed1327a..f33ccec1 100644 --- a/app/Console/Commands/RecalculateAttendanceCommand.php +++ b/app/Console/Commands/RecalculateAttendanceCommand.php @@ -8,13 +8,12 @@ use Illuminate\Console\Command; class RecalculateAttendanceCommand extends Command { protected $signature = 'attendance:recalculate-summary'; - protected $description = 'Recalculates the attendance summary records from raw attendance data.'; public function handle(AttendanceSummaryRebuildService $service): int { $result = $service->rebuild(); - $this->info('Attendance summary recalculation finished. Inserted: '.$result['inserted']); + $this->info('Attendance summary recalculation finished. Inserted: ' . $result['inserted']); return self::SUCCESS; } diff --git a/app/Console/Commands/SendAbsenteesSummaryCommand.php b/app/Console/Commands/SendAbsenteesSummaryCommand.php index 60fc0d78..6f25f29d 100644 --- a/app/Console/Commands/SendAbsenteesSummaryCommand.php +++ b/app/Console/Commands/SendAbsenteesSummaryCommand.php @@ -8,7 +8,6 @@ use Illuminate\Console\Command; class SendAbsenteesSummaryCommand extends Command { protected $signature = 'attendance:absentees-summary'; - protected $description = 'Sends daily attendance summaries for absences to parents.'; public function handle(AttendanceDailySummaryService $service): int diff --git a/app/Console/Commands/SendLatesSummaryCommand.php b/app/Console/Commands/SendLatesSummaryCommand.php index c5cbd7ad..3489ccaf 100644 --- a/app/Console/Commands/SendLatesSummaryCommand.php +++ b/app/Console/Commands/SendLatesSummaryCommand.php @@ -8,7 +8,6 @@ use Illuminate\Console\Command; class SendLatesSummaryCommand extends Command { protected $signature = 'attendance:lates-summary'; - protected $description = 'Sends daily attendance summaries for lates to parents.'; public function handle(AttendanceDailySummaryService $service): int diff --git a/app/Console/Commands/SendMonthlyPaymentNotificationsCommand.php b/app/Console/Commands/SendMonthlyPaymentNotificationsCommand.php index 07a8ed25..a2ffccf1 100644 --- a/app/Console/Commands/SendMonthlyPaymentNotificationsCommand.php +++ b/app/Console/Commands/SendMonthlyPaymentNotificationsCommand.php @@ -9,7 +9,6 @@ use Illuminate\Console\Command; class SendMonthlyPaymentNotificationsCommand extends Command { protected $signature = 'payments:monthly-reminder {--force} {--email=} {--type=}'; - protected $description = 'Send monthly payment reminders on the first Saturday of every month.'; public function handle(PaymentNotificationService $service): int @@ -20,9 +19,8 @@ class SendMonthlyPaymentNotificationsCommand extends Command if ($email !== '') { $user = User::query()->where('email', $email)->first(); - if (! $user) { + if (!$user) { $this->error('Invalid --email provided.'); - return self::FAILURE; } @@ -32,14 +30,12 @@ class SendMonthlyPaymentNotificationsCommand extends Command 'force' => true, ]); - $this->info('Test reminder sent for '.$email.'.'); - + $this->info('Test reminder sent for ' . $email . '.'); return $result['failed'] > 0 ? self::FAILURE : self::SUCCESS; } - if (! $force && ! $this->isFirstSaturday(now())) { + if (!$force && !$this->isFirstSaturday(now())) { $this->info('Not the first Saturday of the month. Use --force to override.'); - return self::SUCCESS; } diff --git a/app/Console/Commands/SendTestPaymentNotificationCommand.php b/app/Console/Commands/SendTestPaymentNotificationCommand.php index 16873942..63002fbe 100644 --- a/app/Console/Commands/SendTestPaymentNotificationCommand.php +++ b/app/Console/Commands/SendTestPaymentNotificationCommand.php @@ -8,7 +8,6 @@ use Illuminate\Console\Command; class SendTestPaymentNotificationCommand extends Command { protected $signature = 'payments:send-test {--email=} {--type=no_payment}'; - protected $description = 'Send a single test non-payment or installment reminder to a specific email.'; public function handle(PaymentTestNotificationService $service): int @@ -16,20 +15,18 @@ class SendTestPaymentNotificationCommand extends Command $email = (string) $this->option('email'); $type = (string) $this->option('type'); - if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL)) { + if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) { $this->error('Usage: php artisan payments:send-test --email=addr@example.com [--type=no_payment|installment]'); - return self::FAILURE; } $result = $service->send($email, $type); - if (! $result['ok']) { - $this->error('Failed to send test reminder to '.$email.'.'); - + if (!$result['ok']) { + $this->error('Failed to send test reminder to ' . $email . '.'); return self::FAILURE; } - $this->info('Sent test reminder to '.$email.'.'); + $this->info('Sent test reminder to ' . $email . '.'); return self::SUCCESS; } diff --git a/app/Console/Commands/SyncPaypalPaymentsCommand.php b/app/Console/Commands/SyncPaypalPaymentsCommand.php index f101ae11..7a5ba23f 100644 --- a/app/Console/Commands/SyncPaypalPaymentsCommand.php +++ b/app/Console/Commands/SyncPaypalPaymentsCommand.php @@ -8,7 +8,6 @@ use Illuminate\Console\Command; class SyncPaypalPaymentsCommand extends Command { protected $signature = 'payments:sync-paypal {--dry-run} {--report-only}'; - protected $description = 'Sync PayPal payments to internal payments table from paypal_payments.'; public function handle(PaypalPaymentSyncService $service): int @@ -19,7 +18,7 @@ class SyncPaypalPaymentsCommand extends Command $result = $service->sync($dryRun, $reportOnly); $this->info(sprintf('[%s] %d PayPal payments processed.', $result['mode'], $result['processed'])); - if (! empty($result['failed'])) { + if (!empty($result['failed'])) { $this->error(sprintf('[%s] Failed transactions: %s', $result['mode'], implode(', ', $result['failed']))); } diff --git a/app/Events/DeleteUnverifiedUser.php b/app/Events/DeleteUnverifiedUser.php index e033be77..b15e9c7c 100644 --- a/app/Events/DeleteUnverifiedUser.php +++ b/app/Events/DeleteUnverifiedUser.php @@ -4,5 +4,7 @@ namespace App\Events; class DeleteUnverifiedUser { - public function __construct(public int $userId) {} + public function __construct(public int $userId) + { + } } diff --git a/app/Events/WhatsappInvitesSend.php b/app/Events/WhatsappInvitesSend.php index 2a03b39f..af1cf788 100644 --- a/app/Events/WhatsappInvitesSend.php +++ b/app/Events/WhatsappInvitesSend.php @@ -10,5 +10,7 @@ class WhatsappInvitesSend use Dispatchable; use SerializesModels; - public function __construct(public array $payload) {} + public function __construct(public array $payload) + { + } } diff --git a/app/Helpers/app_helpers.php b/app/Helpers/app_helpers.php index 1a8e20b8..7cd96b32 100644 --- a/app/Helpers/app_helpers.php +++ b/app/Helpers/app_helpers.php @@ -3,34 +3,33 @@ use Carbon\CarbonImmutable; use Illuminate\Support\Facades\Hash; -if (! function_exists('utc_now')) { +if (!function_exists('utc_now')) { function utc_now(): string { return CarbonImmutable::now('UTC')->toDateTimeString(); } } -if (! function_exists('local_date')) { +if (!function_exists('local_date')) { function local_date(string $utcDateTime, string $format = 'Y-m-d H:i:s'): string { try { $carbon = CarbonImmutable::parse($utcDateTime)->setTimezone(config('app.timezone')); - return $carbon->format($format); - } catch (Throwable $e) { + } catch (\Throwable $e) { return CarbonImmutable::parse($utcDateTime)->format($format); } } } -if (! function_exists('user_timezone')) { +if (!function_exists('user_timezone')) { function user_timezone(): string { return (string) (config('School')->attendance['timezone'] ?? config('app.timezone', 'America/New_York')); } } -if (! function_exists('pbkdf2_hash')) { +if (!function_exists('pbkdf2_hash')) { function pbkdf2_hash(string $password, string $algo = 'sha256', int $iterations = 100000, int $length = 64): string { $salt = random_bytes(16); @@ -42,7 +41,7 @@ if (! function_exists('pbkdf2_hash')) { } } -if (! function_exists('pbkdf2_verify')) { +if (!function_exists('pbkdf2_verify')) { function pbkdf2_verify(string $password, string $storedHash): bool { $delim = strpos($storedHash, '$') !== false ? '$' : ':'; @@ -63,15 +62,14 @@ if (! function_exists('pbkdf2_verify')) { } $calc = hash_pbkdf2($algo, $password, $salt, (int) $iterations, strlen($derived), true); - return hash_equals($derived, $calc); } } -if (! function_exists('verify_stored_password')) { +if (!function_exists('verify_stored_password')) { function verify_stored_password(string $password, ?string $storedHash): bool { - if (! $storedHash) { + if (!$storedHash) { return false; } diff --git a/app/Http/Controllers/Api/Administrator/AdministratorAbsenceController.php b/app/Http/Controllers/Api/Administrator/AdministratorAbsenceController.php index 696f1ca8..498033ad 100644 --- a/app/Http/Controllers/Api/Administrator/AdministratorAbsenceController.php +++ b/app/Http/Controllers/Api/Administrator/AdministratorAbsenceController.php @@ -13,7 +13,8 @@ class AdministratorAbsenceController extends Controller { public function __construct( protected AdministratorAbsenceService $service - ) {} + ) { + } public function index(): JsonResponse { @@ -33,7 +34,7 @@ class AdministratorAbsenceController extends Controller } $payload = $request->all(); - if (! array_key_exists('dates', $payload) || ! array_key_exists('reason', $payload)) { + if (!array_key_exists('dates', $payload) || !array_key_exists('reason', $payload)) { $json = json_decode($request->getContent() ?: '', true); if (is_array($json)) { $payload = array_merge($payload, $json); diff --git a/app/Http/Controllers/Api/Administrator/AdministratorDashboardController.php b/app/Http/Controllers/Api/Administrator/AdministratorDashboardController.php index bb327ef1..67a82364 100644 --- a/app/Http/Controllers/Api/Administrator/AdministratorDashboardController.php +++ b/app/Http/Controllers/Api/Administrator/AdministratorDashboardController.php @@ -11,7 +11,8 @@ class AdministratorDashboardController extends Controller { public function __construct( protected AdministratorDashboardService $service - ) {} + ) { + } public function metrics(): JsonResponse { @@ -24,4 +25,4 @@ class AdministratorDashboardController extends Controller $this->service->userSearch((string) $request->query('query', '')) ); } -} +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/Administrator/AdministratorEnrollmentController.php b/app/Http/Controllers/Api/Administrator/AdministratorEnrollmentController.php index 44e43c9d..2bc753e6 100644 --- a/app/Http/Controllers/Api/Administrator/AdministratorEnrollmentController.php +++ b/app/Http/Controllers/Api/Administrator/AdministratorEnrollmentController.php @@ -14,7 +14,8 @@ class AdministratorEnrollmentController extends Controller { public function __construct( protected AdministratorEnrollmentService $service - ) {} + ) { + } public function index(Request $request): JsonResponse { @@ -38,13 +39,13 @@ class AdministratorEnrollmentController extends Controller } $payload = $request->all(); - if (! array_key_exists('enrollment_status', $payload)) { + if (!array_key_exists('enrollment_status', $payload)) { $json = json_decode($request->getContent() ?: '', true); if (is_array($json) && array_key_exists('enrollment_status', $json)) { $payload['enrollment_status'] = $json['enrollment_status']; } } - if (! array_key_exists('enrollment_status', $payload)) { + if (!array_key_exists('enrollment_status', $payload)) { $payload['enrollment_status'] = $request->query('enrollment_status'); } diff --git a/app/Http/Controllers/Api/Administrator/AdministratorNotificationController.php b/app/Http/Controllers/Api/Administrator/AdministratorNotificationController.php index 67a0a5be..efc793ff 100644 --- a/app/Http/Controllers/Api/Administrator/AdministratorNotificationController.php +++ b/app/Http/Controllers/Api/Administrator/AdministratorNotificationController.php @@ -12,7 +12,8 @@ class AdministratorNotificationController extends Controller { public function __construct( protected AdministratorNotificationService $service - ) {} + ) { + } public function alerts(): JsonResponse { @@ -22,7 +23,7 @@ class AdministratorNotificationController extends Controller public function saveAlerts(Request $request): JsonResponse { $payload = $request->all(); - if (! array_key_exists('subjects', $payload)) { + if (!array_key_exists('subjects', $payload)) { $json = json_decode($request->getContent() ?: '', true); if (is_array($json)) { $payload = array_merge($payload, $json); @@ -59,7 +60,7 @@ class AdministratorNotificationController extends Controller public function savePrintRecipients(Request $request): JsonResponse { $payload = $request->all(); - if (! array_key_exists('notify', $payload)) { + if (!array_key_exists('notify', $payload)) { $json = json_decode($request->getContent() ?: '', true); if (is_array($json)) { $payload = array_merge($payload, $json); diff --git a/app/Http/Controllers/Api/Administrator/AdministratorPromotionController.php b/app/Http/Controllers/Api/Administrator/AdministratorPromotionController.php index 5631b479..320ae177 100644 --- a/app/Http/Controllers/Api/Administrator/AdministratorPromotionController.php +++ b/app/Http/Controllers/Api/Administrator/AdministratorPromotionController.php @@ -16,18 +16,18 @@ use App\Http\Resources\Promotions\PromotionReminderResource; use App\Http\Resources\Promotions\StudentPromotionResource; use App\Models\PromotionAuditLog; use App\Models\PromotionReminderLog; -use App\Models\SectionPlacementBatch; use App\Models\StudentPromotionRecord; use App\Services\Promotions\LevelProgressionService; -use App\Services\Promotions\Placement\SectionPlacementPreviewService; use App\Services\Promotions\PromotionAuditService; use App\Services\Promotions\PromotionEligibilityService; use App\Services\Promotions\PromotionEnrollmentService; use App\Services\Promotions\PromotionQueryService; use App\Services\Promotions\PromotionReminderService; use App\Services\Promotions\PromotionStatusService; -use Illuminate\Http\JsonResponse; +use App\Services\Promotions\Placement\SectionPlacementPreviewService; +use App\Models\SectionPlacementBatch; use Illuminate\Http\Request; +use Illuminate\Http\JsonResponse; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; use Symfony\Component\HttpFoundation\Response; @@ -54,7 +54,6 @@ class AdministratorPromotionController extends BaseApiController public function index(AdminListPromotionsRequest $request): JsonResponse { $result = $this->query->list($request->filters()); - return response()->json([ 'ok' => true, 'data' => StudentPromotionResource::collection($result['data']), @@ -74,7 +73,6 @@ class AdministratorPromotionController extends BaseApiController if ($record instanceof JsonResponse) { return $record; } - return response()->json([ 'ok' => true, 'data' => new StudentPromotionResource($this->query->detail($record)), @@ -84,7 +82,6 @@ class AdministratorPromotionController extends BaseApiController public function summary(AdminListPromotionsRequest $request): JsonResponse { $counts = $this->query->countsByStatus($request->filters()); - return response()->json([ 'ok' => true, 'counts_by_status' => $counts, @@ -128,7 +125,6 @@ class AdministratorPromotionController extends BaseApiController }; } catch (\Throwable $e) { Log::error('Promotion eligibility evaluation failed', ['exception' => $e]); - return response()->json([ 'ok' => false, 'message' => 'Failed to evaluate promotion eligibility.', @@ -141,6 +137,7 @@ class AdministratorPromotionController extends BaseApiController ]); } + public function createPlacementPreview(Request $request): JsonResponse { $payload = $request->validate([ @@ -160,7 +157,6 @@ class AdministratorPromotionController extends BaseApiController ); } catch (\Throwable $e) { Log::error('Section placement preview generation failed', ['exception' => $e]); - return response()->json([ 'ok' => false, 'message' => $e->getMessage(), @@ -176,7 +172,7 @@ class AdministratorPromotionController extends BaseApiController public function showPlacementBatch(int $batchId): JsonResponse { $batch = SectionPlacementBatch::query()->find($batchId); - if (! $batch) { + if (!$batch) { return response()->json(['ok' => false, 'message' => 'Placement batch not found.'], Response::HTTP_NOT_FOUND); } @@ -192,7 +188,6 @@ class AdministratorPromotionController extends BaseApiController $batch = $this->sectionPlacement->finalize($batchId, $this->getCurrentUserId()); } catch (\Throwable $e) { Log::error('Section placement finalization failed', ['batch_id' => $batchId, 'exception' => $e]); - return response()->json([ 'ok' => false, 'message' => $e->getMessage(), @@ -216,7 +211,7 @@ class AdministratorPromotionController extends BaseApiController $userId = $this->getCurrentUserId(); try { - $updated = ! empty($payload['force']) + $updated = !empty($payload['force']) ? $this->statusService->forceStatus($record, $payload['status'], $userId, $payload['notes'] ?? null) : $this->statusService->transition($record, $payload['status'], $userId, $payload['notes'] ?? null); } catch (\InvalidArgumentException $e) { @@ -249,7 +244,7 @@ class AdministratorPromotionController extends BaseApiController return $record; } $records = collect([$record]); - } elseif ($applyTo === 'filter' && ! empty($payload['promotion_ids'])) { + } elseif ($applyTo === 'filter' && !empty($payload['promotion_ids'])) { $records = StudentPromotionRecord::query() ->whereIn('promotion_id', $payload['promotion_ids']) ->get(); @@ -310,7 +305,6 @@ class AdministratorPromotionController extends BaseApiController 'promotion_id' => $promotionId, 'exception' => $e, ]); - return response()->json([ 'ok' => false, 'message' => 'Failed to send reminder.', @@ -327,7 +321,6 @@ class AdministratorPromotionController extends BaseApiController { $userId = $this->getCurrentUserId(); $result = $this->reminders->dispatchScheduledReminders(null, $userId); - return response()->json([ 'ok' => true, 'result' => $result, @@ -344,7 +337,6 @@ class AdministratorPromotionController extends BaseApiController ->forPromotion((int) $record->getKey()) ->orderByDesc('id') ->get(); - return response()->json([ 'ok' => true, 'reminders' => PromotionReminderResource::collection($rows), @@ -361,7 +353,6 @@ class AdministratorPromotionController extends BaseApiController ->forPromotion((int) $record->getKey()) ->orderByDesc('id') ->get(); - return response()->json([ 'ok' => true, 'entries' => PromotionAuditLogResource::collection($rows), @@ -371,7 +362,6 @@ class AdministratorPromotionController extends BaseApiController public function expireDeadlines(): JsonResponse { $result = $this->enrollmentService->markExpiredDeadlines(null, $this->getCurrentUserId()); - return response()->json([ 'ok' => true, 'result' => $result, @@ -414,7 +404,6 @@ class AdministratorPromotionController extends BaseApiController public function levelProgressions(): JsonResponse { $rows = $this->progression->list(false); - return response()->json([ 'ok' => true, 'levels' => LevelProgressionResource::collection($rows), @@ -424,7 +413,6 @@ class AdministratorPromotionController extends BaseApiController public function upsertLevelProgression(UpsertLevelProgressionRequest $request): JsonResponse { $row = $this->progression->upsertMapping($request->validated()); - return response()->json([ 'ok' => true, 'level' => new LevelProgressionResource($row), @@ -434,7 +422,6 @@ class AdministratorPromotionController extends BaseApiController public function seedLevelProgressions(): JsonResponse { $created = $this->progression->seedDefaults(); - return response()->json([ 'ok' => true, 'created' => $created, @@ -444,13 +431,12 @@ class AdministratorPromotionController extends BaseApiController private function findOrFail(int $promotionId): StudentPromotionRecord|JsonResponse { $record = StudentPromotionRecord::query()->find($promotionId); - if (! $record) { + if (!$record) { return response()->json([ 'ok' => false, 'message' => 'Promotion record not found.', ], Response::HTTP_NOT_FOUND); } - return $record; } } diff --git a/app/Http/Controllers/Api/Administrator/AdministratorTeacherSubmissionController.php b/app/Http/Controllers/Api/Administrator/AdministratorTeacherSubmissionController.php index 4a1e7ced..6960ac32 100644 --- a/app/Http/Controllers/Api/Administrator/AdministratorTeacherSubmissionController.php +++ b/app/Http/Controllers/Api/Administrator/AdministratorTeacherSubmissionController.php @@ -13,7 +13,8 @@ class AdministratorTeacherSubmissionController extends Controller { public function __construct( protected AdministratorTeacherSubmissionService $service - ) {} + ) { + } public function index(Request $request): JsonResponse { diff --git a/app/Http/Controllers/Api/Administrator/EmergencyContactController.php b/app/Http/Controllers/Api/Administrator/EmergencyContactController.php index 022989b3..5c685cf9 100644 --- a/app/Http/Controllers/Api/Administrator/EmergencyContactController.php +++ b/app/Http/Controllers/Api/Administrator/EmergencyContactController.php @@ -18,7 +18,8 @@ class EmergencyContactController extends Controller public function __construct( private EmergencyContactDirectoryService $directoryService, private EmergencyContactCrudService $crudService - ) {} + ) { + } public function index(Request $request): JsonResponse { @@ -37,10 +38,10 @@ class EmergencyContactController extends Controller $payload = $validator->validated(); $parentIds = []; - if (! empty($payload['parent_ids'])) { + if (!empty($payload['parent_ids'])) { $parentIds = array_values(array_unique(array_map('intval', $payload['parent_ids']))); } - if (! empty($payload['parent_id'])) { + if (!empty($payload['parent_id'])) { $parentIds[] = (int) $payload['parent_id']; } $parentIds = array_values(array_unique(array_filter($parentIds))); diff --git a/app/Http/Controllers/Api/Administrator/TeacherClassAssignmentController.php b/app/Http/Controllers/Api/Administrator/TeacherClassAssignmentController.php index 494cc994..7f841d28 100644 --- a/app/Http/Controllers/Api/Administrator/TeacherClassAssignmentController.php +++ b/app/Http/Controllers/Api/Administrator/TeacherClassAssignmentController.php @@ -61,6 +61,9 @@ class TeacherClassAssignmentController extends BaseApiController ], $status); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Attendance/AdminAttendanceApiController.php b/app/Http/Controllers/Api/Attendance/AdminAttendanceApiController.php index 14bfd63b..9530777e 100644 --- a/app/Http/Controllers/Api/Attendance/AdminAttendanceApiController.php +++ b/app/Http/Controllers/Api/Attendance/AdminAttendanceApiController.php @@ -23,8 +23,8 @@ class AdminAttendanceApiController extends Controller { return new DailyAttendanceResource( $this->queryService->buildDailyAttendanceData( - (string) $request->query('semester', $this->attendanceService->currentSemester()), - (string) $request->query('school_year', $this->attendanceService->currentSchoolYear()) + (string)$request->query('semester', $this->attendanceService->currentSemester()), + (string)$request->query('school_year', $this->attendanceService->currentSchoolYear()) ) ); } @@ -60,4 +60,4 @@ class AdminAttendanceApiController extends Controller return response()->json(['message' => $e->getMessage()], 422); } } -} +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/Attendance/AttendanceCommentTemplateController.php b/app/Http/Controllers/Api/Attendance/AttendanceCommentTemplateController.php index 33aa8ee2..6ae9a5ad 100644 --- a/app/Http/Controllers/Api/Attendance/AttendanceCommentTemplateController.php +++ b/app/Http/Controllers/Api/Attendance/AttendanceCommentTemplateController.php @@ -14,7 +14,8 @@ class AttendanceCommentTemplateController extends Controller public function __construct( protected AttendanceCommentTemplateService $service, protected ApplicationUrlService $urls, - ) {} + ) { + } public function bootstrapUrls(): JsonResponse { @@ -74,7 +75,7 @@ class AttendanceCommentTemplateController extends Controller } $data = $validator->validated(); - if (! array_key_exists('is_active', $data)) { + if (!array_key_exists('is_active', $data)) { $data['is_active'] = true; } diff --git a/app/Http/Controllers/Api/Attendance/EarlyDismissalsController.php b/app/Http/Controllers/Api/Attendance/EarlyDismissalsController.php index 4c9a6cba..fffae4f7 100644 --- a/app/Http/Controllers/Api/Attendance/EarlyDismissalsController.php +++ b/app/Http/Controllers/Api/Attendance/EarlyDismissalsController.php @@ -9,6 +9,7 @@ use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Validator; use Symfony\Component\HttpFoundation\Response; @@ -26,7 +27,7 @@ class EarlyDismissalsController extends BaseApiController public function index(Request $request): JsonResponse { $schoolYear = $request->query('school_year'); - $semester = $request->query('semester'); + $semester = $request->query('semester'); $query = DB::table('parent_attendance_reports as par') ->select([ @@ -61,15 +62,15 @@ class EarlyDismissalsController extends BaseApiController foreach ($rows as $row) { $date = $row->report_date ?? 'Unknown'; $groups[$date][] = [ - 'id' => $row->id, - 'firstname' => $row->firstname, - 'lastname' => $row->lastname, + 'id' => $row->id, + 'firstname' => $row->firstname, + 'lastname' => $row->lastname, 'class_section_name' => $row->class_section_name, - 'dismiss_time' => $row->dismiss_time, - 'reason' => $row->reason, - 'status' => $row->status, - 'school_year' => $row->school_year, - 'semester' => $row->semester, + 'dismiss_time' => $row->dismiss_time, + 'reason' => $row->reason, + 'status' => $row->status, + 'school_year' => $row->school_year, + 'semester' => $row->semester, ]; } @@ -81,13 +82,13 @@ class EarlyDismissalsController extends BaseApiController $signatureByDate = []; foreach ($signatures as $sig) { $signatureByDate[(string) $sig->report_date] = [ - 'filename' => $sig->filename, + 'filename' => $sig->filename, 'original_name' => $sig->original_name, ]; } return $this->success([ - 'groups' => $groups, + 'groups' => $groups, 'signatureByDate' => $signatureByDate, ]); } @@ -107,7 +108,7 @@ class EarlyDismissalsController extends BaseApiController ]) ->leftJoin('student_class as sc', function ($j) { $j->on('sc.student_id', '=', 's.id') - ->where('sc.school_year', '=', Configuration::getConfigValueByKey('school_year')); + ->where('sc.school_year', '=', Configuration::getConfigValueByKey('school_year')); }) ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'sc.class_section_id') ->where('s.is_active', 1) @@ -124,10 +125,10 @@ class EarlyDismissalsController extends BaseApiController public function store(Request $request): JsonResponse { $validator = Validator::make($request->all(), [ - 'student_id' => ['required', 'integer', 'min:1', 'exists:students,id'], - 'date' => ['required', 'date_format:Y-m-d'], + 'student_id' => ['required', 'integer', 'min:1', 'exists:students,id'], + 'date' => ['required', 'date_format:Y-m-d'], 'dismiss_time' => ['required', 'date_format:H:i'], - 'reason' => ['nullable', 'string', 'max:2000'], + 'reason' => ['nullable', 'string', 'max:2000'], ]); if ($validator->fails()) { @@ -137,7 +138,7 @@ class EarlyDismissalsController extends BaseApiController $data = $validator->validated(); $schoolYear = (string) Configuration::getConfigValueByKey('school_year'); - $semester = (string) Configuration::getConfigValueByKey('semester'); + $semester = (string) Configuration::getConfigValueByKey('semester'); $sc = DB::table('student_class') ->where('student_id', $data['student_id']) @@ -152,18 +153,18 @@ class EarlyDismissalsController extends BaseApiController ->value('parent_id') ?? Auth::id(); DB::table('parent_attendance_reports')->insert([ - 'parent_id' => $parentId ?? Auth::id(), - 'student_id' => $data['student_id'], + 'parent_id' => $parentId ?? Auth::id(), + 'student_id' => $data['student_id'], 'class_section_id' => $classSectionId, - 'report_date' => $data['date'], - 'type' => 'early_dismissal', - 'dismiss_time' => $data['dismiss_time'], - 'reason' => $data['reason'] ?? null, - 'semester' => $semester, - 'school_year' => $schoolYear, - 'status' => 'new', - 'created_at' => now(), - 'updated_at' => now(), + 'report_date' => $data['date'], + 'type' => 'early_dismissal', + 'dismiss_time' => $data['dismiss_time'], + 'reason' => $data['reason'] ?? null, + 'semester' => $semester, + 'school_year' => $schoolYear, + 'status' => 'new', + 'created_at' => now(), + 'updated_at' => now(), ]); return $this->success([], 'Early dismissal saved.', Response::HTTP_CREATED); @@ -176,9 +177,9 @@ class EarlyDismissalsController extends BaseApiController public function uploadSignature(Request $request): JsonResponse { $validator = Validator::make($request->all(), [ - 'report_date' => ['required', 'date_format:Y-m-d'], - 'school_year' => ['nullable', 'string', 'max:16'], - 'semester' => ['nullable', 'string', 'max:32'], + 'report_date' => ['required', 'date_format:Y-m-d'], + 'school_year' => ['nullable', 'string', 'max:16'], + 'semester' => ['nullable', 'string', 'max:32'], 'signature_file' => ['required', 'file', 'mimes:jpg,jpeg,png,webp,gif,pdf', 'max:5120'], ]); @@ -186,13 +187,13 @@ class EarlyDismissalsController extends BaseApiController return $this->respondValidationError($validator->errors()->toArray()); } - $file = $request->file('signature_file'); + $file = $request->file('signature_file'); $reportDate = $request->input('report_date'); $schoolYear = $request->input('school_year') ?: (string) Configuration::getConfigValueByKey('school_year'); - $semester = $request->input('semester') ?: (string) Configuration::getConfigValueByKey('semester'); + $semester = $request->input('semester') ?: (string) Configuration::getConfigValueByKey('semester'); - $dir = storage_path('uploads/early_dismissal_signatures'); - if (! is_dir($dir)) { + $dir = storage_path('uploads/early_dismissal_signatures'); + if (!is_dir($dir)) { mkdir($dir, 0755, true); } @@ -202,21 +203,21 @@ class EarlyDismissalsController extends BaseApiController ->where('semester', $semester) ->first(); - if ($existing?->filename && file_exists($dir.'/'.$existing->filename)) { - unlink($dir.'/'.$existing->filename); + if ($existing?->filename && file_exists($dir . '/' . $existing->filename)) { + unlink($dir . '/' . $existing->filename); } - $filename = uniqid('sig_', true).'.'.$file->getClientOriginalExtension(); + $filename = uniqid('sig_', true) . '.' . $file->getClientOriginalExtension(); $file->move($dir, $filename); EarlyDismissalSignature::updateOrCreate( ['report_date' => $reportDate, 'school_year' => $schoolYear, 'semester' => $semester], [ - 'filename' => $filename, + 'filename' => $filename, 'original_name' => $file->getClientOriginalName(), - 'mime_type' => $file->getClientMimeType(), - 'file_size' => $file->getSize(), - 'uploaded_by' => Auth::id(), + 'mime_type' => $file->getClientMimeType(), + 'file_size' => $file->getSize(), + 'uploaded_by' => Auth::id(), ] ); diff --git a/app/Http/Controllers/Api/Attendance/LateSlipLogsController.php b/app/Http/Controllers/Api/Attendance/LateSlipLogsController.php index 38237ebc..ba8d3b8e 100644 --- a/app/Http/Controllers/Api/Attendance/LateSlipLogsController.php +++ b/app/Http/Controllers/Api/Attendance/LateSlipLogsController.php @@ -42,7 +42,7 @@ class LateSlipLogsController extends BaseApiController public function show(int $id): JsonResponse { $log = $this->queryService->find($id); - if (! $log) { + if (!$log) { return $this->error('Late slip log not found.', Response::HTTP_NOT_FOUND); } @@ -56,7 +56,7 @@ class LateSlipLogsController extends BaseApiController public function destroy(int $id): JsonResponse { $log = $this->queryService->find($id); - if (! $log) { + if (!$log) { return $this->error('Late slip log not found.', Response::HTTP_NOT_FOUND); } @@ -65,12 +65,11 @@ class LateSlipLogsController extends BaseApiController try { $deleted = $this->commandService->delete($log); } catch (\Throwable $e) { - Log::error('Late slip log delete failed: '.$e->getMessage()); - + Log::error('Late slip log delete failed: ' . $e->getMessage()); return $this->error('Unable to delete late slip log.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! $deleted) { + if (!$deleted) { return $this->error('Unable to delete late slip log.', Response::HTTP_INTERNAL_SERVER_ERROR); } diff --git a/app/Http/Controllers/Api/Attendance/StaffAttendanceApiController.php b/app/Http/Controllers/Api/Attendance/StaffAttendanceApiController.php index 4af30f2a..5fa4ae9f 100644 --- a/app/Http/Controllers/Api/Attendance/StaffAttendanceApiController.php +++ b/app/Http/Controllers/Api/Attendance/StaffAttendanceApiController.php @@ -23,8 +23,8 @@ class StaffAttendanceApiController extends Controller { return new StaffMonthResource( $this->staffAttendanceService->monthData( - (string) $request->query('semester'), - (string) $request->query('school_year') + (string)$request->query('semester'), + (string)$request->query('school_year') ) ); } @@ -33,9 +33,9 @@ class StaffAttendanceApiController extends Controller { return new AdminAttendanceResource( $this->staffAttendanceService->adminsAttendanceData( - (string) $request->query('date'), - (string) $request->query('semester'), - (string) $request->query('school_year') + (string)$request->query('date'), + (string)$request->query('semester'), + (string)$request->query('school_year') ) ); } @@ -75,9 +75,9 @@ class StaffAttendanceApiController extends Controller public function monthCsv(Request $request): StreamedResponse { return $this->staffAttendanceService->monthCsv( - (string) $request->query('semester'), - (string) $request->query('school_year'), - (string) $request->query('scope') + (string)$request->query('semester'), + (string)$request->query('school_year'), + (string)$request->query('scope') ); } -} +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/Attendance/TeacherAttendanceApiController.php b/app/Http/Controllers/Api/Attendance/TeacherAttendanceApiController.php index fbefa6cd..84170381 100644 --- a/app/Http/Controllers/Api/Attendance/TeacherAttendanceApiController.php +++ b/app/Http/Controllers/Api/Attendance/TeacherAttendanceApiController.php @@ -21,10 +21,10 @@ class TeacherAttendanceApiController extends Controller public function grid(Request $request): TeacherGridResource { - $semester = (string) ($request->query('semester') ?: $this->attendanceService->currentSemester()); - $schoolYear = (string) ($request->query('school_year') ?: $this->attendanceService->currentSchoolYear()); - $date = (string) ($request->query('date') ?: now()->toDateString()); - $sectionCode = (int) $request->query('class_section_id', 0); + $semester = (string)($request->query('semester') ?: $this->attendanceService->currentSemester()); + $schoolYear = (string)($request->query('school_year') ?: $this->attendanceService->currentSchoolYear()); + $date = (string)($request->query('date') ?: now()->toDateString()); + $sectionCode = (int)$request->query('class_section_id', 0); return new TeacherGridResource( $this->queryService->teacherGrid($semester, $schoolYear, $date, $sectionCode) @@ -42,7 +42,7 @@ class TeacherAttendanceApiController extends Controller return new TeacherAttendanceFormResource( $this->queryService->teacherAttendanceFormData( $guard, - (int) $request->query('class_section_id', 0) + (int)$request->query('class_section_id', 0) ) ); } catch (Throwable $e) { @@ -66,6 +66,9 @@ class TeacherAttendanceApiController extends Controller } } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); @@ -75,4 +78,4 @@ class TeacherAttendanceApiController extends Controller return $userId; } -} +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/AttendanceManagement/AttendanceManagementController.php b/app/Http/Controllers/Api/AttendanceManagement/AttendanceManagementController.php index ab97f748..906dfad8 100644 --- a/app/Http/Controllers/Api/AttendanceManagement/AttendanceManagementController.php +++ b/app/Http/Controllers/Api/AttendanceManagement/AttendanceManagementController.php @@ -41,9 +41,7 @@ class AttendanceManagementController extends BaseApiController 'reason' => ['nullable', 'string', 'max:255'], 'notes' => ['nullable', 'string'], ]); - if ($validator->fails()) { - return $this->respondValidationError($validator->errors()->toArray()); - } + if ($validator->fails()) return $this->respondValidationError($validator->errors()->toArray()); try { return $this->success(['event' => $this->service->manualEntry($validator->validated(), $request->user())], 'Manual attendance entry recorded.', Response::HTTP_CREATED); } catch (\InvalidArgumentException $e) { @@ -65,9 +63,7 @@ class AttendanceManagementController extends BaseApiController 'authorized' => ['nullable'], 'reason' => ['nullable', 'string', 'max:255'], ]); - if ($validator->fails()) { - return $this->respondValidationError($validator->errors()->toArray()); - } + if ($validator->fails()) return $this->respondValidationError($validator->errors()->toArray()); try { return $this->success(['event' => $this->service->badgeScan($validator->validated(), $request->user())], 'Badge scan classified.'); } catch (\InvalidArgumentException $e) { @@ -95,9 +91,7 @@ class AttendanceManagementController extends BaseApiController 'reason' => ['nullable', 'string', 'max:255'], 'notes' => ['nullable', 'string'], ]); - if ($validator->fails()) { - return $this->respondValidationError($validator->errors()->toArray()); - } + if ($validator->fails()) return $this->respondValidationError($validator->errors()->toArray()); try { return $this->success(['event' => $this->service->exitEntry($validator->validated(), $request->user())], 'Exit attendance entry recorded.', Response::HTTP_CREATED); } catch (\InvalidArgumentException $e) { @@ -119,9 +113,7 @@ class AttendanceManagementController extends BaseApiController 'report_status' => ['nullable', 'string', 'max:48'], 'reason' => ['nullable', 'string', 'max:255'], ]); - if ($validator->fails()) { - return $this->respondValidationError($validator->errors()->toArray()); - } + if ($validator->fails()) return $this->respondValidationError($validator->errors()->toArray()); try { return $this->success(['event' => $this->service->markAbsent($validator->validated(), $request->user())], 'Absence recorded.', Response::HTTP_CREATED); } catch (\InvalidArgumentException $e) { @@ -138,9 +130,7 @@ class AttendanceManagementController extends BaseApiController 'final_decision' => ['nullable', 'string', 'max:255'], 'notes' => ['nullable', 'string'], ]); - if ($validator->fails()) { - return $this->respondValidationError($validator->errors()->toArray()); - } + if ($validator->fails()) return $this->respondValidationError($validator->errors()->toArray()); try { return $this->success(['event' => $this->service->completeFollowUp($id, $validator->validated(), $request->user())], 'Follow-up completed.'); } catch (\RuntimeException $e) { @@ -157,9 +147,7 @@ class AttendanceManagementController extends BaseApiController 'slip_number' => ['nullable', 'string', 'max:64'], 'late_slip_log_id' => ['nullable', 'integer'], ]); - if ($validator->fails()) { - return $this->respondValidationError($validator->errors()->toArray()); - } + if ($validator->fails()) return $this->respondValidationError($validator->errors()->toArray()); try { return $this->success(['reprint' => $this->service->reprintLateSlip($id, $validator->validated(), $request->user())], 'Late slip reprint logged.', Response::HTTP_CREATED); } catch (\RuntimeException $e) { diff --git a/app/Http/Controllers/Api/AttendanceTracking/AttendanceTrackingController.php b/app/Http/Controllers/Api/AttendanceTracking/AttendanceTrackingController.php index 503524f5..6d53db9f 100644 --- a/app/Http/Controllers/Api/AttendanceTracking/AttendanceTrackingController.php +++ b/app/Http/Controllers/Api/AttendanceTracking/AttendanceTrackingController.php @@ -12,7 +12,8 @@ class AttendanceTrackingController extends Controller { public function __construct( protected AttendanceTrackingService $service - ) {} + ) { + } public function pendingViolations(Request $request): JsonResponse { diff --git a/app/Http/Controllers/Api/Auth/AuthController.php b/app/Http/Controllers/Api/Auth/AuthController.php index 91ffbbb4..b7eb842d 100644 --- a/app/Http/Controllers/Api/Auth/AuthController.php +++ b/app/Http/Controllers/Api/Auth/AuthController.php @@ -39,7 +39,7 @@ class AuthController extends BaseApiController } $user = User::query()->whereRaw('LOWER(email) = ?', [$email])->first(); - if (! $user) { + if (!$user) { $security->logIpAttempt((string) $ip); return response()->json([ @@ -70,7 +70,7 @@ class AuthController extends BaseApiController $security->logSuccessfulLogin($user->fresh(), $request); $fresh = $user->fresh(); - if (! $fresh) { + if (!$fresh) { return response()->json([ 'status' => false, 'message' => 'Invalid email or password.', @@ -100,7 +100,7 @@ class AuthController extends BaseApiController public function me(): JsonResponse { $user = Auth::user(); - if (! $user) { + if (!$user) { return $this->respondError('Unauthorized.', 401); } diff --git a/app/Http/Controllers/Api/Auth/IpBanController.php b/app/Http/Controllers/Api/Auth/IpBanController.php index 4eaf314c..3f45f8c8 100644 --- a/app/Http/Controllers/Api/Auth/IpBanController.php +++ b/app/Http/Controllers/Api/Auth/IpBanController.php @@ -44,7 +44,7 @@ class IpBanController extends BaseApiController public function show(int $id): JsonResponse { $ban = $this->queryService->find($id); - if (! $ban) { + if (!$ban) { return $this->error('IP record not found.', Response::HTTP_NOT_FOUND); } @@ -67,12 +67,11 @@ class IpBanController extends BaseApiController try { $ban = $this->commandService->banNow($id ? (int) $id : null, $ip ? (string) $ip : null, $hours); } catch (\Throwable $e) { - Log::error('IP ban failed: '.$e->getMessage()); - + Log::error('IP ban failed: ' . $e->getMessage()); return $this->error('Unable to ban IP.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! $ban) { + if (!$ban) { return $this->error('IP record not found.', Response::HTTP_NOT_FOUND); } @@ -91,10 +90,9 @@ class IpBanController extends BaseApiController try { if ($all) { $count = $this->commandService->unbanAll(); - return $this->success([ 'count' => $count, - ], $count.' IP(s) unbanned.'); + ], $count . ' IP(s) unbanned.'); } $ban = $this->commandService->unbanOne( @@ -102,12 +100,11 @@ class IpBanController extends BaseApiController $validated['ip'] ?? null ); } catch (\Throwable $e) { - Log::error('IP unban failed: '.$e->getMessage()); - + Log::error('IP unban failed: ' . $e->getMessage()); return $this->error('Unable to unban IP.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! $ban) { + if (!$ban) { return $this->error('IP record not found.', Response::HTTP_NOT_FOUND); } diff --git a/app/Http/Controllers/Api/Auth/RegisterController.php b/app/Http/Controllers/Api/Auth/RegisterController.php index 5e1cafef..0de4fd44 100644 --- a/app/Http/Controllers/Api/Auth/RegisterController.php +++ b/app/Http/Controllers/Api/Auth/RegisterController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers\Api\Auth; use App\Http\Controllers\Api\Core\BaseApiController; -use App\Http\Requests\Auth\RegisterRequest; use App\Http\Resources\Auth\RegisterResource; use App\Services\Auth\ApiRegistrationService; use App\Services\Auth\RegistrationCaptchaService; @@ -51,7 +50,7 @@ class RegisterController extends BaseApiController ]); } - $validator = Validator::make($request->all(), RegisterRequest::ruleset()); + $validator = Validator::make($request->all(), \App\Http\Requests\Auth\RegisterRequest::ruleset()); if ($validator->fails()) { return response()->json([ 'message' => 'Validation failed.', diff --git a/app/Http/Controllers/Api/Auth/RolePermissionController.php b/app/Http/Controllers/Api/Auth/RolePermissionController.php index e4e15825..3395caac 100644 --- a/app/Http/Controllers/Api/Auth/RolePermissionController.php +++ b/app/Http/Controllers/Api/Auth/RolePermissionController.php @@ -56,7 +56,7 @@ class RolePermissionController extends BaseApiController public function showRole(int $roleId): JsonResponse { $role = Role::query()->find($roleId); - if (! $role) { + if (!$role) { return $this->error('Role not found.', Response::HTTP_NOT_FOUND); } @@ -70,8 +70,7 @@ class RolePermissionController extends BaseApiController try { $role = $this->roleCrudService->create($request->validated()); } catch (\Throwable $e) { - Log::error('Role store failed: '.$e->getMessage()); - + Log::error('Role store failed: ' . $e->getMessage()); return $this->error('Failed to create role.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -83,15 +82,14 @@ class RolePermissionController extends BaseApiController public function updateRole(RoleUpdateRequest $request, int $roleId): JsonResponse { $role = Role::query()->find($roleId); - if (! $role) { + if (!$role) { return $this->error('Role not found.', Response::HTTP_NOT_FOUND); } try { $role = $this->roleCrudService->update($role, $request->validated()); } catch (\Throwable $e) { - Log::error('Role update failed: '.$e->getMessage()); - + Log::error('Role update failed: ' . $e->getMessage()); return $this->error('Failed to update role.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -103,15 +101,14 @@ class RolePermissionController extends BaseApiController public function deleteRole(int $roleId): JsonResponse { $role = Role::query()->find($roleId); - if (! $role) { + if (!$role) { return $this->error('Role not found.', Response::HTTP_NOT_FOUND); } try { $this->roleCrudService->delete($role); } catch (\Throwable $e) { - Log::error('Role delete failed: '.$e->getMessage()); - + Log::error('Role delete failed: ' . $e->getMessage()); return $this->error('Failed to delete role.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -147,12 +144,11 @@ class RolePermissionController extends BaseApiController $actorId ); } catch (\Throwable $e) { - Log::error('Assign roles failed: '.$e->getMessage()); - + Log::error('Assign roles failed: ' . $e->getMessage()); return $this->error('Failed to update roles.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to update roles.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -173,7 +169,7 @@ class RolePermissionController extends BaseApiController public function showPermission(int $permissionId): JsonResponse { $permission = Permission::query()->find($permissionId); - if (! $permission) { + if (!$permission) { return $this->error('Permission not found.', Response::HTTP_NOT_FOUND); } @@ -187,8 +183,7 @@ class RolePermissionController extends BaseApiController try { $permission = $this->permissionCrudService->create($request->validated()); } catch (\Throwable $e) { - Log::error('Permission store failed: '.$e->getMessage()); - + Log::error('Permission store failed: ' . $e->getMessage()); return $this->error('Failed to create permission.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -200,15 +195,14 @@ class RolePermissionController extends BaseApiController public function updatePermission(PermissionUpdateRequest $request, int $permissionId): JsonResponse { $permission = Permission::query()->find($permissionId); - if (! $permission) { + if (!$permission) { return $this->error('Permission not found.', Response::HTTP_NOT_FOUND); } try { $permission = $this->permissionCrudService->update($permission, $request->validated()); } catch (\Throwable $e) { - Log::error('Permission update failed: '.$e->getMessage()); - + Log::error('Permission update failed: ' . $e->getMessage()); return $this->error('Failed to update permission.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -220,15 +214,14 @@ class RolePermissionController extends BaseApiController public function deletePermission(int $permissionId): JsonResponse { $permission = Permission::query()->find($permissionId); - if (! $permission) { + if (!$permission) { return $this->error('Permission not found.', Response::HTTP_NOT_FOUND); } try { $this->permissionCrudService->delete($permission); } catch (\Throwable $e) { - Log::error('Permission delete failed: '.$e->getMessage()); - + Log::error('Permission delete failed: ' . $e->getMessage()); return $this->error('Failed to delete permission.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -249,14 +242,16 @@ class RolePermissionController extends BaseApiController try { $this->permissionService->saveRolePermissions($roleId, $request->validated()['permissions'] ?? []); } catch (\Throwable $e) { - Log::error('Role permissions update failed: '.$e->getMessage()); - + Log::error('Role permissions update failed: ' . $e->getMessage()); return $this->error('Failed to update role permissions.', Response::HTTP_INTERNAL_SERVER_ERROR); } return $this->success(null, 'Permissions saved successfully.'); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Auth/RoleSwitcherController.php b/app/Http/Controllers/Api/Auth/RoleSwitcherController.php index 569cbf1d..e5427d11 100644 --- a/app/Http/Controllers/Api/Auth/RoleSwitcherController.php +++ b/app/Http/Controllers/Api/Auth/RoleSwitcherController.php @@ -6,9 +6,9 @@ use App\Http\Controllers\Api\Core\BaseApiController; use App\Http\Requests\Roles\RoleSwitchRequest; use App\Services\Roles\RoleSwitchService; use Illuminate\Http\JsonResponse; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpFoundation\Response; class RoleSwitcherController extends BaseApiController { @@ -56,6 +56,9 @@ class RoleSwitcherController extends BaseApiController ], 'Role switched successfully.'); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Auth/SessionTimeoutController.php b/app/Http/Controllers/Api/Auth/SessionTimeoutController.php index b29f19e9..6cb3a380 100644 --- a/app/Http/Controllers/Api/Auth/SessionTimeoutController.php +++ b/app/Http/Controllers/Api/Auth/SessionTimeoutController.php @@ -19,7 +19,8 @@ class SessionTimeoutController extends Controller public function __construct( private ApplicationUrlService $urls, - ) {} + ) { + } /** * Returns timeout metadata for the web portal. diff --git a/app/Http/Controllers/Api/Badges/BadgeController.php b/app/Http/Controllers/Api/Badges/BadgeController.php index b9777caa..9a2d1345 100644 --- a/app/Http/Controllers/Api/Badges/BadgeController.php +++ b/app/Http/Controllers/Api/Badges/BadgeController.php @@ -17,7 +17,8 @@ class BadgeController extends Controller protected BadgePdfService $badgePdfService, protected BadgePrintLogService $badgePrintLogService, protected BadgeFormDataService $badgeFormDataService - ) {} + ) { + } public function generatePdf(Request $request) { @@ -165,7 +166,7 @@ class BadgeController extends Controller if (is_string($ids)) { $ids = array_filter(array_map('trim', explode(',', $ids)), 'strlen'); - } elseif (! is_array($ids)) { + } elseif (!is_array($ids)) { $ids = $ids ? [$ids] : []; } @@ -198,7 +199,7 @@ class BadgeController extends Controller if (is_string($ids)) { $ids = array_filter(array_map('trim', explode(',', $ids)), 'strlen'); - } elseif (! is_array($ids)) { + } elseif (!is_array($ids)) { $ids = $ids ? [$ids] : []; } @@ -207,6 +208,9 @@ class BadgeController extends Controller return array_values(array_filter($ids, static fn ($v) => $v > 0)); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/BaseApiController.php b/app/Http/Controllers/Api/BaseApiController.php index 2134d855..00e32be0 100644 --- a/app/Http/Controllers/Api/BaseApiController.php +++ b/app/Http/Controllers/Api/BaseApiController.php @@ -4,4 +4,6 @@ namespace App\Http\Controllers\Api; use App\Http\Controllers\Api\Core\BaseApiController as CoreBaseApiController; -class BaseApiController extends CoreBaseApiController {} +class BaseApiController extends CoreBaseApiController +{ +} diff --git a/app/Http/Controllers/Api/ClassPreparation/ClassPreparationController.php b/app/Http/Controllers/Api/ClassPreparation/ClassPreparationController.php index 42bbbc45..86732288 100644 --- a/app/Http/Controllers/Api/ClassPreparation/ClassPreparationController.php +++ b/app/Http/Controllers/Api/ClassPreparation/ClassPreparationController.php @@ -20,16 +20,15 @@ use Symfony\Component\HttpFoundation\Response; class ClassPreparationController extends BaseApiController { private ClassPreparationService $service; - private StickerCountService $stickerCounts; - private ClassRosterService $roster; public function __construct( ClassPreparationService $service, StickerCountService $stickerCounts, ClassRosterService $roster - ) { + ) + { parent::__construct(); $this->service = $service; $this->stickerCounts = $stickerCounts; @@ -78,8 +77,7 @@ class ClassPreparationController extends BaseApiController try { $count = $this->service->saveAdjustments($classSectionId, $schoolYear, $validated['adjustments']); } catch (\Throwable $e) { - Log::error('Class prep adjustment save failed: '.$e->getMessage()); - + Log::error('Class prep adjustment save failed: ' . $e->getMessage()); return $this->error('Unable to save adjustments.', Response::HTTP_INTERNAL_SERVER_ERROR); } diff --git a/app/Http/Controllers/Api/ClassProgress/ClassProgressController.php b/app/Http/Controllers/Api/ClassProgress/ClassProgressController.php index cda25c37..45ddf489 100644 --- a/app/Http/Controllers/Api/ClassProgress/ClassProgressController.php +++ b/app/Http/Controllers/Api/ClassProgress/ClassProgressController.php @@ -94,9 +94,8 @@ class ClassProgressController extends BaseApiController $filters['semester'] = $filters['semester'] ?? ($meta['semester'] ?? null); $paginator = $this->queryService->listReports($auth, $filters); - if (! empty($filters['group_by_week'])) { + if (!empty($filters['group_by_week'])) { $grouped = ClassProgressGroupCollection::fromPaginator($paginator); - return $this->respondSuccess($grouped, 'Progress reports retrieved.'); } @@ -136,7 +135,6 @@ class ClassProgressController extends BaseApiController Log::error('Failed to create class progress reports.', [ 'error' => $e->getMessage(), ]); - return $this->respondError('Unable to save progress reports.', 500); } @@ -172,7 +170,6 @@ class ClassProgressController extends BaseApiController Log::error('Failed to update class progress report.', [ 'error' => $e->getMessage(), ]); - return $this->respondError('Unable to update progress report.', 500); } @@ -187,7 +184,6 @@ class ClassProgressController extends BaseApiController Log::error('Failed to delete class progress report.', [ 'error' => $e->getMessage(), ]); - return $this->respondError('Unable to delete progress report.', 500); } @@ -197,7 +193,7 @@ class ClassProgressController extends BaseApiController public function downloadAttachment(int $attachment): BinaryFileResponse|JsonResponse { $record = ClassProgressAttachment::query()->find($attachment); - if (! $record || ! $record->file_path) { + if (!$record || !$record->file_path) { return $this->respondError('Attachment not found.', 404); } @@ -206,12 +202,11 @@ class ClassProgressController extends BaseApiController } $path = $this->attachmentService->resolvePath($record->file_path); - if (! $path) { + if (!$path) { return $this->respondError('Attachment missing.', 404); } $downloadName = $record->original_name ?: basename($path); - return response()->download($path, $downloadName); } @@ -219,12 +214,12 @@ class ClassProgressController extends BaseApiController { $this->authorize('view', $class_progress); - if (! $class_progress->attachment_path) { + if (!$class_progress->attachment_path) { return $this->respondError('Attachment not found.', 404); } $path = $this->attachmentService->resolvePath($class_progress->attachment_path); - if (! $path) { + if (!$path) { return $this->respondError('Attachment missing.', 404); } @@ -233,18 +228,19 @@ class ClassProgressController extends BaseApiController /** * @param mixed $user + * @return User|JsonResponse */ private function requireAuthenticatedUser($user): User|JsonResponse { - if (! $user instanceof User) { + if (!$user instanceof User) { $user = auth()->user(); } - if (! $user instanceof User) { + if (!$user instanceof User) { $user = $this->laravelRequest->user(); } - if (! $user instanceof User) { + if (!$user instanceof User) { return $this->respondError('Unauthorized.', Response::HTTP_UNAUTHORIZED); } diff --git a/app/Http/Controllers/Api/Classes/ClassController.php b/app/Http/Controllers/Api/Classes/ClassController.php index 1a5f86c0..09991bc2 100644 --- a/app/Http/Controllers/Api/Classes/ClassController.php +++ b/app/Http/Controllers/Api/Classes/ClassController.php @@ -53,7 +53,7 @@ class ClassController extends BaseApiController $section = $this->queryService->find((int) $classSection->id); - if (! $section) { + if (!$section) { return $this->error('Class section not found.', Response::HTTP_NOT_FOUND); } @@ -88,7 +88,7 @@ class ClassController extends BaseApiController { $this->authorize('delete', $classSection); - if (! $this->commandService->delete($classSection)) { + if (!$this->commandService->delete($classSection)) { return $this->error('Class section not found.', Response::HTTP_NOT_FOUND); } @@ -125,8 +125,7 @@ class ClassController extends BaseApiController try { $created = $this->seedService->seedDefaults(); } catch (\Throwable $e) { - Log::error('Seeding default classes failed: '.$e->getMessage()); - + Log::error('Seeding default classes failed: ' . $e->getMessage()); return $this->error('Unable to seed default classes.', Response::HTTP_INTERNAL_SERVER_ERROR); } diff --git a/app/Http/Controllers/Api/Communication/CommunicationController.php b/app/Http/Controllers/Api/Communication/CommunicationController.php index b8281e11..e55655bc 100644 --- a/app/Http/Controllers/Api/Communication/CommunicationController.php +++ b/app/Http/Controllers/Api/Communication/CommunicationController.php @@ -14,13 +14,9 @@ use Illuminate\Http\Request; class CommunicationController extends BaseApiController { private CommunicationStudentService $students; - private CommunicationTemplateService $templates; - private CommunicationFamilyService $families; - private CommunicationPreviewService $previewService; - private CommunicationSendService $sendService; public function __construct( @@ -80,7 +76,7 @@ class CommunicationController extends BaseApiController $teacherName = $this->resolveTeacherName(); $result = $this->previewService->buildPreview($templateKey, $studentId, $familyId, $vars, $teacherName); - if (! $result['ok']) { + if (!$result['ok']) { return response()->json([ 'ok' => false, 'message' => $result['message'] ?? 'Preview failed.', @@ -120,7 +116,7 @@ class CommunicationController extends BaseApiController } $student = $this->students->getStudentBasic($studentId); - if (! $student) { + if (!$student) { return response()->json([ 'ok' => false, 'message' => 'Student not found.', @@ -141,11 +137,11 @@ class CommunicationController extends BaseApiController 'recipients' => $recipients, 'cc' => $cc, 'bcc' => $bcc, - 'student_name' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')), + 'student_name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')), 'sent_by' => $senderId, ]); - if (! $result['ok']) { + if (!$result['ok']) { return response()->json([ 'ok' => false, 'message' => 'Failed to send email.', @@ -179,14 +175,15 @@ class CommunicationController extends BaseApiController { $user = auth()->user(); if ($user) { - $name = trim(($user->firstname ?? '').' '.($user->lastname ?? '')); - + $name = trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? '')); return $name !== '' ? $name : 'Teacher'; } - return 'Teacher'; } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/CompetitionScores/CompetitionScoresController.php b/app/Http/Controllers/Api/CompetitionScores/CompetitionScoresController.php index a1feb69b..09dc3cfa 100644 --- a/app/Http/Controllers/Api/CompetitionScores/CompetitionScoresController.php +++ b/app/Http/Controllers/Api/CompetitionScores/CompetitionScoresController.php @@ -14,11 +14,8 @@ use Illuminate\Http\Request; class CompetitionScoresController extends BaseApiController { private CompetitionScoresContextService $contextService; - private CompetitionScoresQueryService $queryService; - private CompetitionScoresRosterService $rosterService; - private CompetitionScoresSaveService $saveService; public function __construct( @@ -103,7 +100,7 @@ class CompetitionScoresController extends BaseApiController } $competition = Competition::query()->find($id); - if (! $competition) { + if (!$competition) { return response()->json([ 'ok' => false, 'message' => 'Competition not found.', @@ -123,7 +120,7 @@ class CompetitionScoresController extends BaseApiController ], 422); } - if (! in_array($classSectionId, $allowedClassIds, true)) { + if (!in_array($classSectionId, $allowedClassIds, true)) { return response()->json([ 'ok' => false, 'message' => 'You are not assigned to that class.', @@ -173,7 +170,7 @@ class CompetitionScoresController extends BaseApiController } $competition = Competition::query()->find($id); - if (! $competition) { + if (!$competition) { return response()->json([ 'ok' => false, 'message' => 'Competition not found.', @@ -197,7 +194,7 @@ class CompetitionScoresController extends BaseApiController ], 422); } - if (! in_array($classSectionId, $allowedClassIds, true)) { + if (!in_array($classSectionId, $allowedClassIds, true)) { return response()->json([ 'ok' => false, 'message' => 'You are not assigned to that class.', @@ -208,7 +205,7 @@ class CompetitionScoresController extends BaseApiController $scores = is_array($scores) ? $scores : []; [$cleanScores, $invalidScores] = $this->saveService->filterScores($scores); - if (! empty($invalidScores)) { + if (!empty($invalidScores)) { return response()->json([ 'ok' => false, 'message' => 'Scores must be whole numbers (no decimals).', @@ -225,6 +222,9 @@ class CompetitionScoresController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Core/BaseApiController.php b/app/Http/Controllers/Api/Core/BaseApiController.php index 6cb46bb2..3b05ff3c 100644 --- a/app/Http/Controllers/Api/Core/BaseApiController.php +++ b/app/Http/Controllers/Api/Core/BaseApiController.php @@ -6,7 +6,6 @@ use App\Http\Controllers\Controller; use App\Models\User; use Illuminate\Contracts\Validation\Validator as ValidatorContract; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; -use Illuminate\Database\Query\Builder; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -17,8 +16,7 @@ use Symfony\Component\HttpFoundation\Response; class BaseApiController extends Controller { protected Request $laravelRequest; - - protected ?ValidatorContract $validator = null; + protected ValidatorContract|null $validator = null; public function __construct() { @@ -28,19 +26,19 @@ class BaseApiController extends Controller protected function success($data = null, string $message = 'Success', int $code = Response::HTTP_OK): JsonResponse { return response()->json([ - 'status' => true, + 'status' => true, 'message' => $message, - 'data' => $data, + 'data' => $data, ], $code); } protected function error(string $message = 'An error occurred', int $code = Response::HTTP_BAD_REQUEST, ?array $errors = null): JsonResponse { $payload = [ - 'status' => false, + 'status' => false, 'message' => $message, ]; - if (! empty($errors)) { + if (!empty($errors)) { $payload['errors'] = $errors; } @@ -93,7 +91,6 @@ class BaseApiController extends Controller { $payload = $this->payloadData(); $errors = $this->validateRequest($payload, $rules); - return empty($errors); } @@ -103,7 +100,6 @@ class BaseApiController extends Controller if (is_array($json)) { return $json; } - return array_merge($this->laravelRequest->query->all(), $this->laravelRequest->request->all()); } @@ -120,88 +116,71 @@ class BaseApiController extends Controller continue; } if (preg_match('/^max_length\\[(\\d+)\\]$/', $part, $m)) { - $result[] = 'max:'.$m[1]; - + $result[] = 'max:' . $m[1]; continue; } if (preg_match('/^min_length\\[(\\d+)\\]$/', $part, $m)) { - $result[] = 'min:'.$m[1]; - + $result[] = 'min:' . $m[1]; continue; } if (preg_match('/^in_list\\[(.+)\\]$/', $part, $m)) { - $result[] = 'in:'.$m[1]; - + $result[] = 'in:' . $m[1]; continue; } if (preg_match('/^greater_than_equal_to\\[(.+)\\]$/', $part, $m)) { - $result[] = 'gte:'.$m[1]; - + $result[] = 'gte:' . $m[1]; continue; } if (preg_match('/^less_than_equal_to\\[(.+)\\]$/', $part, $m)) { - $result[] = 'lte:'.$m[1]; - + $result[] = 'lte:' . $m[1]; continue; } if (preg_match('/^valid_date\\[(.+)\\]$/', $part, $m)) { - $result[] = 'date_format:'.$m[1]; - + $result[] = 'date_format:' . $m[1]; continue; } if ($part === 'valid_email') { $result[] = 'email'; - continue; } if ($part === 'permit_empty') { $result[] = 'nullable'; - continue; } if (preg_match('/^is_unique\\[([^\\.]+)\\.([^\\]]+)\\]$/', $part, $m)) { - $result[] = 'unique:'.$m[1].','.$m[2]; - + $result[] = 'unique:' . $m[1] . ',' . $m[2]; continue; } if ($part === 'string') { $result[] = 'string'; - continue; } if ($part === 'integer') { $result[] = 'integer'; - continue; } if ($part === 'numeric') { $result[] = 'numeric'; - continue; } if ($part === 'required') { $result[] = 'required'; - continue; } if ($part === 'alpha_numeric') { $result[] = 'alpha_num'; - continue; } if ($part === 'in_array') { $result[] = 'in_array'; - continue; } if ($part === 'valid_url') { $result[] = 'url'; - continue; } if (strpos($part, 'max_size') === 0) { $result[] = str_replace('max_size', 'max', $part); - continue; } $result[] = $part; @@ -212,11 +191,11 @@ class BaseApiController extends Controller protected function paginate($source, int $page = 1, int $perPage = 20): array { - $page = max(1, $page); + $page = max(1, $page); $perPage = max(1, $perPage); - $offset = ($page - 1) * $perPage; + $offset = ($page - 1) * $perPage; - if ($source instanceof EloquentBuilder || $source instanceof Builder) { + if ($source instanceof EloquentBuilder || $source instanceof \Illuminate\Database\Query\Builder) { $total = $source->toBase()->getCountForPagination(); $items = $source->offset($offset)->limit($perPage)->get()->toArray(); } elseif (is_array($source)) { @@ -227,9 +206,9 @@ class BaseApiController extends Controller 'data' => [], 'pagination' => [ 'current_page' => $page, - 'per_page' => $perPage, - 'total' => 0, - 'total_pages' => 0, + 'per_page' => $perPage, + 'total' => 0, + 'total_pages' => 0, ], ]; } @@ -238,9 +217,9 @@ class BaseApiController extends Controller 'data' => array_values($items), 'pagination' => [ 'current_page' => $page, - 'per_page' => $perPage, - 'total' => $total, - 'total_pages' => (int) ceil($total / $perPage), + 'per_page' => $perPage, + 'total' => $total, + 'total_pages' => (int) ceil($total / $perPage), ], ]; } @@ -254,30 +233,29 @@ class BaseApiController extends Controller if ($userId <= 0) { $userId = (int) (optional($this->laravelRequest->user())->id ?? 0); } - return $userId > 0 ? $userId : null; } protected function getCurrentUser(): ?object { $userId = $this->getCurrentUserId(); - if (! $userId) { + if (!$userId) { return null; } /** @var User|null $row */ $row = User::query()->find($userId); - if (! $row) { + if (!$row) { return null; } $firstname = (string) ($row->firstname ?? ''); - $lastname = (string) ($row->lastname ?? ''); - $email = $row->email; + $lastname = (string) ($row->lastname ?? ''); + $email = $row->email; - $name = trim($firstname.' '.$lastname); + $name = trim($firstname . ' ' . $lastname); if ($name === '') { - $name = $email ?? 'User #'.$userId; + $name = $email ?? 'User #' . $userId; } try { @@ -291,13 +269,13 @@ class BaseApiController extends Controller ->values() ->all(); } catch (\Throwable $e) { - Log::error('Unable to load user roles: '.$e->getMessage()); + Log::error('Unable to load user roles: ' . $e->getMessage()); $roles = []; } return (object) [ - 'id' => (int) $userId, - 'name' => $name, + 'id' => (int) $userId, + 'name' => $name, 'email' => $email, 'roles' => $roles, ]; diff --git a/app/Http/Controllers/Api/Discounts/DiscountController.php b/app/Http/Controllers/Api/Discounts/DiscountController.php index 0784d899..f1fb5183 100644 --- a/app/Http/Controllers/Api/Discounts/DiscountController.php +++ b/app/Http/Controllers/Api/Discounts/DiscountController.php @@ -17,11 +17,8 @@ use Illuminate\Http\JsonResponse; class DiscountController extends BaseApiController { private DiscountContextService $context; - private DiscountVoucherService $voucherService; - private DiscountParentService $parentService; - private DiscountApplyService $applyService; public function __construct( @@ -72,7 +69,6 @@ class DiscountController extends BaseApiController public function listVouchers(): JsonResponse { $vouchers = $this->voucherService->listAll(); - return response()->json([ 'ok' => true, 'vouchers' => DiscountVoucherResource::collection($vouchers), @@ -82,7 +78,6 @@ class DiscountController extends BaseApiController public function storeVoucher(StoreDiscountVoucherRequest $request): JsonResponse { $voucher = $this->voucherService->create($request->validated()); - return response()->json([ 'ok' => true, 'voucher' => new DiscountVoucherResource($voucher), @@ -92,7 +87,6 @@ class DiscountController extends BaseApiController public function updateVoucher(UpdateDiscountVoucherRequest $request, int $id): JsonResponse { $voucher = $this->voucherService->update($id, $request->validated()); - return response()->json([ 'ok' => true, 'voucher' => new DiscountVoucherResource($voucher), @@ -102,7 +96,6 @@ class DiscountController extends BaseApiController public function showVoucher(int $id): JsonResponse { $voucher = $this->voucherService->find($id); - return response()->json([ 'ok' => true, 'voucher' => new DiscountVoucherResource($voucher), @@ -112,12 +105,14 @@ class DiscountController extends BaseApiController public function deleteVoucher(int $id): JsonResponse { $this->voucherService->delete($id); - return response()->json([ 'ok' => true, ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Email/BroadcastEmailController.php b/app/Http/Controllers/Api/Email/BroadcastEmailController.php index 200506b4..797d579c 100644 --- a/app/Http/Controllers/Api/Email/BroadcastEmailController.php +++ b/app/Http/Controllers/Api/Email/BroadcastEmailController.php @@ -14,13 +14,9 @@ use Illuminate\Http\Request; class BroadcastEmailController extends BaseApiController { private BroadcastEmailSenderOptionsService $senderOptions; - private BroadcastEmailRecipientService $recipients; - private BroadcastEmailComposerService $composer; - private BroadcastEmailDispatchService $dispatch; - private BroadcastEmailImageService $imageService; public function __construct( @@ -144,7 +140,7 @@ class BroadcastEmailController extends BaseApiController public function uploadImage(Request $request): JsonResponse { $file = $request->file('image'); - if (! $file || ! $file->isValid()) { + if (!$file || !$file->isValid()) { return response()->json([ 'success' => false, 'error' => 'No image uploaded', @@ -152,7 +148,7 @@ class BroadcastEmailController extends BaseApiController } $result = $this->imageService->store($file); - if (! $result['ok']) { + if (!$result['ok']) { return response()->json([ 'success' => false, 'error' => $result['error'] ?? 'Upload failed', @@ -178,7 +174,6 @@ class BroadcastEmailController extends BaseApiController foreach (explode(',', $value) as $piece) { $ids[] = (int) $piece; } - continue; } $ids[] = (int) $value; diff --git a/app/Http/Controllers/Api/Email/EmailController.php b/app/Http/Controllers/Api/Email/EmailController.php index 78d1d5de..696316a9 100644 --- a/app/Http/Controllers/Api/Email/EmailController.php +++ b/app/Http/Controllers/Api/Email/EmailController.php @@ -46,7 +46,7 @@ class EmailController extends BaseApiController $attachments ); - if (! $ok) { + if (!$ok) { return response()->json([ 'ok' => false, 'message' => 'Email failed to send.', diff --git a/app/Http/Controllers/Api/Email/EmailExtractorController.php b/app/Http/Controllers/Api/Email/EmailExtractorController.php index e1b797cd..f63cbd33 100644 --- a/app/Http/Controllers/Api/Email/EmailExtractorController.php +++ b/app/Http/Controllers/Api/Email/EmailExtractorController.php @@ -8,6 +8,7 @@ use App\Http\Resources\Email\EmailExtractorCompareResource; use App\Http\Resources\Email\EmailExtractorEmailsResource; use App\Services\Email\EmailExtractorService; use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; class EmailExtractorController extends BaseApiController { diff --git a/app/Http/Controllers/Api/Exams/ExamDraftController.php b/app/Http/Controllers/Api/Exams/ExamDraftController.php index 4798260f..b434813c 100644 --- a/app/Http/Controllers/Api/Exams/ExamDraftController.php +++ b/app/Http/Controllers/Api/Exams/ExamDraftController.php @@ -49,7 +49,7 @@ class ExamDraftController extends BaseApiController } $result = $this->teacherService->store($guard, $request->validated(), $request->file('draft_file')); - if (! $result['ok']) { + if (!$result['ok']) { return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Unable to save.'], 422); } @@ -85,7 +85,7 @@ class ExamDraftController extends BaseApiController } $result = $this->adminService->uploadLegacy($guard, $request->validated(), $request->file('old_exam_file')); - if (! $result['ok']) { + if (!$result['ok']) { return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Unable to save.'], 422); } @@ -103,7 +103,7 @@ class ExamDraftController extends BaseApiController } $result = $this->adminService->review($guard, $request->validated(), $request->file('final_file')); - if (! $result['ok']) { + if (!$result['ok']) { return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Unable to save.'], 422); } @@ -113,6 +113,9 @@ class ExamDraftController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Expenses/ExpenseController.php b/app/Http/Controllers/Api/Expenses/ExpenseController.php index 771b573e..a7440736 100644 --- a/app/Http/Controllers/Api/Expenses/ExpenseController.php +++ b/app/Http/Controllers/Api/Expenses/ExpenseController.php @@ -51,7 +51,6 @@ class ExpenseController extends BaseApiController $rows = $this->queryService->listAll(); $rows = array_map(function ($row) { $row['receipt_url'] = $this->receiptService->receiptUrl($row['receipt_path'] ?? null); - return $row; }, $rows); @@ -64,7 +63,7 @@ class ExpenseController extends BaseApiController public function show(int $id): JsonResponse { $row = $this->queryService->findById($id); - if (! $row) { + if (!$row) { return response()->json(['ok' => false, 'message' => 'Expense not found.'], 404); } @@ -122,7 +121,7 @@ class ExpenseController extends BaseApiController } $expense = Expense::query()->find($id); - if (! $expense) { + if (!$expense) { return response()->json(['ok' => false, 'message' => 'Expense not found.'], 404); } @@ -132,7 +131,7 @@ class ExpenseController extends BaseApiController if ($request->hasFile('receipt')) { $receiptName = $this->receiptService->storeReceipt($request->file('receipt')); } - if (! empty($payload['remove_receipt'])) { + if (!empty($payload['remove_receipt'])) { $receiptName = null; } @@ -177,7 +176,7 @@ class ExpenseController extends BaseApiController } $expense = Expense::query()->find($id); - if (! $expense) { + if (!$expense) { return response()->json(['ok' => false, 'message' => 'Expense not found.'], 404); } @@ -191,6 +190,9 @@ class ExpenseController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/ExtraCharges/ExtraChargesController.php b/app/Http/Controllers/Api/ExtraCharges/ExtraChargesController.php index 696880de..fac7d96d 100644 --- a/app/Http/Controllers/Api/ExtraCharges/ExtraChargesController.php +++ b/app/Http/Controllers/Api/ExtraCharges/ExtraChargesController.php @@ -103,7 +103,7 @@ class ExtraChargesController extends BaseApiController public function update(UpdateExtraChargeRequest $request, int $id): JsonResponse { $charge = AdditionalCharge::query()->find($id); - if (! $charge) { + if (!$charge) { return response()->json(['ok' => false, 'error' => 'Charge not found'], 404); } @@ -126,7 +126,7 @@ class ExtraChargesController extends BaseApiController public function void(int $id): JsonResponse { $charge = AdditionalCharge::query()->find($id); - if (! $charge) { + if (!$charge) { return response()->json(['ok' => false, 'error' => 'Charge not found'], 404); } @@ -140,7 +140,7 @@ class ExtraChargesController extends BaseApiController public function reverse(int $id): JsonResponse { $charge = AdditionalCharge::query()->find($id); - if (! $charge) { + if (!$charge) { return response()->json(['ok' => false, 'error' => 'Charge not found'], 404); } @@ -151,6 +151,9 @@ class ExtraChargesController extends BaseApiController ], $ok ? 200 : 422); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Family/FamilyAdminController.php b/app/Http/Controllers/Api/Family/FamilyAdminController.php index cc0ff8e9..02d2007c 100644 --- a/app/Http/Controllers/Api/Family/FamilyAdminController.php +++ b/app/Http/Controllers/Api/Family/FamilyAdminController.php @@ -72,7 +72,7 @@ class FamilyAdminController extends BaseApiController $schoolYear ); - if (! $family) { + if (!$family) { return $this->error('Family not found.', Response::HTTP_NOT_FOUND); } @@ -92,9 +92,8 @@ class FamilyAdminController extends BaseApiController $payload['reply_to_name'] ?? null ); - if (! $ok) { + 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); } diff --git a/app/Http/Controllers/Api/Family/FamilyController.php b/app/Http/Controllers/Api/Family/FamilyController.php index 047755c4..63f3c6ad 100644 --- a/app/Http/Controllers/Api/Family/FamilyController.php +++ b/app/Http/Controllers/Api/Family/FamilyController.php @@ -53,8 +53,7 @@ class FamilyController extends BaseApiController try { $result = $this->mutationService->bootstrapFamilies(); } catch (\Throwable $e) { - Log::error('Family bootstrap failed: '.$e->getMessage()); - + Log::error('Family bootstrap failed: ' . $e->getMessage()); return $this->error('Family bootstrap failed.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -70,7 +69,7 @@ class FamilyController extends BaseApiController (string) ($payload['relation'] ?? 'secondary') ); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Unable to attach guardian.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -89,12 +88,11 @@ class FamilyController extends BaseApiController (string) ($payload['relation'] ?? 'secondary') ); } catch (\Throwable $e) { - Log::error('Attach guardian by email failed: '.$e->getMessage()); - + 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)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Unable to attach guardian.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -158,12 +156,11 @@ class FamilyController extends BaseApiController try { $result = $this->mutationService->importSecondParentsFromLegacy(); } catch (\Throwable $e) { - Log::error('Legacy second parent import failed: '.$e->getMessage()); - + Log::error('Legacy second parent import failed: ' . $e->getMessage()); return $this->error('Legacy import failed.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! ($result['ok'] ?? true)) { + if (!($result['ok'] ?? true)) { return $this->error($result['message'] ?? 'Legacy import failed.', Response::HTTP_UNPROCESSABLE_ENTITY); } diff --git a/app/Http/Controllers/Api/Finance/BalanceCarryforwardController.php b/app/Http/Controllers/Api/Finance/BalanceCarryforwardController.php index 43b268c9..2a8af7d8 100644 --- a/app/Http/Controllers/Api/Finance/BalanceCarryforwardController.php +++ b/app/Http/Controllers/Api/Finance/BalanceCarryforwardController.php @@ -38,14 +38,12 @@ class BalanceCarryforwardController extends Controller public function waive(CarryforwardAdjustmentRequest $request, int $carryforward): JsonResponse { $data = $request->validated(); - return response()->json(['ok' => true, 'carryforward' => $this->service->waive($carryforward, (float) $data['amount'], $data['reason'] ?? null, optional($request->user())->id)]); } public function adjust(CarryforwardAdjustmentRequest $request, int $carryforward): JsonResponse { $data = $request->validated(); - return response()->json(['ok' => true, 'carryforward' => $this->service->adjust($carryforward, (float) $data['amount'], $data['reason'] ?? null)]); } @@ -57,13 +55,10 @@ class BalanceCarryforwardController extends Controller public function reportCsv(Request $request): StreamedResponse { $rows = $this->service->csvRows($this->service->report($request->query())); - return response()->streamDownload(function () use ($rows) { $out = fopen('php://output', 'w'); - foreach ($rows as $row) { - fputcsv($out, $row); - } + foreach ($rows as $row) fputcsv($out, $row); fclose($out); - }, 'carryforward_report_'.date('Ymd_His').'.csv', ['Content-Type' => 'text/csv']); + }, 'carryforward_report_' . date('Ymd_His') . '.csv', ['Content-Type' => 'text/csv']); } } diff --git a/app/Http/Controllers/Api/Finance/ChargeController.php b/app/Http/Controllers/Api/Finance/ChargeController.php index 6ae5ea37..ccb535ca 100644 --- a/app/Http/Controllers/Api/Finance/ChargeController.php +++ b/app/Http/Controllers/Api/Finance/ChargeController.php @@ -143,6 +143,9 @@ class ChargeController extends BaseApiController ], $status); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Finance/EventChargeController.php b/app/Http/Controllers/Api/Finance/EventChargeController.php index e5ed0654..8d85d5e3 100644 --- a/app/Http/Controllers/Api/Finance/EventChargeController.php +++ b/app/Http/Controllers/Api/Finance/EventChargeController.php @@ -15,24 +15,15 @@ class EventChargeController extends Controller public function index(Request $request): JsonResponse { $q = EventCharge::query(); - foreach (['parent_id', 'student_id', 'event_id', 'school_year', 'semester'] as $field) { - if ($request->filled($field)) { - $q->where($field, $request->query($field)); - } + foreach (['parent_id','student_id','event_id','school_year','semester'] as $field) { + if ($request->filled($field)) $q->where($field, $request->query($field)); } if ($request->filled('status')) { $status = $request->query('status'); - if (Schema::hasColumn('event_charges', 'status')) { - $q->where('status', $status); - } elseif ($status === 'paid') { - $q->where('event_paid', 1); - } elseif ($status === 'pending') { - $q->where(function ($qq) { - $qq->whereNull('event_paid')->orWhere('event_paid', 0); - }); - } + if (Schema::hasColumn('event_charges', 'status')) $q->where('status', $status); + elseif ($status === 'paid') $q->where('event_paid', 1); + elseif ($status === 'pending') $q->where(function ($qq) { $qq->whereNull('event_paid')->orWhere('event_paid', 0); }); } - return response()->json(['ok' => true, 'event_charges' => $q->orderByDesc('id')->paginate((int) $request->query('per_page', 25))]); } @@ -40,11 +31,8 @@ class EventChargeController extends Controller { $data = $this->normalizePayload($request->validated()); $data['created_by'] = optional($request->user())->id; - if (Schema::hasColumn('event_charges', 'status')) { - $data['status'] = $data['status'] ?? 'draft'; - } + if (Schema::hasColumn('event_charges', 'status')) $data['status'] = $data['status'] ?? 'draft'; $charge = EventCharge::query()->create($data); - return response()->json(['ok' => true, 'event_charge' => $charge], 201); } @@ -57,7 +45,6 @@ class EventChargeController extends Controller { $charge = EventCharge::query()->findOrFail($eventCharge); $charge->fill($this->normalizePayload($request->validated()))->save(); - return response()->json(['ok' => true, 'event_charge' => $charge->fresh()]); } @@ -69,58 +56,38 @@ class EventChargeController extends Controller public function approve(int $eventCharge): JsonResponse { $charge = EventCharge::query()->findOrFail($eventCharge); - if (Schema::hasColumn('event_charges', 'status')) { - $charge->status = 'approved'; - } - if (Schema::hasColumn('event_charges', 'charged')) { - $charge->charged = 1; - } + if (Schema::hasColumn('event_charges', 'status')) $charge->status = 'approved'; + if (Schema::hasColumn('event_charges', 'charged')) $charge->charged = 1; $charge->save(); - return response()->json(['ok' => true, 'event_charge' => $charge->fresh()]); } public function void(int $eventCharge): JsonResponse { $charge = EventCharge::query()->findOrFail($eventCharge); - if (Schema::hasColumn('event_charges', 'status')) { - $charge->status = 'voided'; - } - if (Schema::hasColumn('event_charges', 'charged')) { - $charge->charged = 0; - } + if (Schema::hasColumn('event_charges', 'status')) $charge->status = 'voided'; + if (Schema::hasColumn('event_charges', 'charged')) $charge->charged = 0; $charge->save(); - return response()->json(['ok' => true, 'event_charge' => $charge->fresh()]); } public function attachToInvoice(Request $request, int $eventCharge): JsonResponse { - $request->validate(['invoice_id' => ['required', 'integer']]); + $request->validate(['invoice_id' => ['required','integer']]); $charge = EventCharge::query()->findOrFail($eventCharge); $invoiceId = (int) $request->input('invoice_id'); - abort_if(! DB::table('invoices')->where('id', $invoiceId)->exists(), 404, 'Invoice not found.'); - if (Schema::hasColumn('event_charges', 'invoice_id')) { - $charge->invoice_id = $invoiceId; - } - if (Schema::hasColumn('event_charges', 'status')) { - $charge->status = 'invoiced'; - } - if (Schema::hasColumn('event_charges', 'charged')) { - $charge->charged = 1; - } + abort_if(!DB::table('invoices')->where('id', $invoiceId)->exists(), 404, 'Invoice not found.'); + if (Schema::hasColumn('event_charges', 'invoice_id')) $charge->invoice_id = $invoiceId; + if (Schema::hasColumn('event_charges', 'status')) $charge->status = 'invoiced'; + if (Schema::hasColumn('event_charges', 'charged')) $charge->charged = 1; $charge->save(); - - return response()->json(['ok' => true, 'event_charge' => $charge->fresh(), 'warning' => Schema::hasColumn('event_charges', 'invoice_id') ? null : 'invoice_id column does not exist; charge marked as charged only.']); + return response()->json(['ok' => true, 'event_charge' => $charge->fresh(), 'warning' => Schema::hasColumn('event_charges','invoice_id') ? null : 'invoice_id column does not exist; charge marked as charged only.']); } private function normalizePayload(array $data): array { - if (isset($data['title']) && ! isset($data['event_name'])) { - $data['event_name'] = $data['title']; - } + if (isset($data['title']) && !isset($data['event_name'])) $data['event_name'] = $data['title']; unset($data['title'], $data['invoice_id']); - - return array_filter($data, fn ($v) => $v !== null); + return array_filter($data, fn($v) => $v !== null); } } diff --git a/app/Http/Controllers/Api/Finance/FinanceNotificationController.php b/app/Http/Controllers/Api/Finance/FinanceNotificationController.php index 6b0e7740..6b17e1a6 100644 --- a/app/Http/Controllers/Api/Finance/FinanceNotificationController.php +++ b/app/Http/Controllers/Api/Finance/FinanceNotificationController.php @@ -16,7 +16,7 @@ class FinanceNotificationController extends Controller public function sendPaymentReceipt(Request $request, int $payment): JsonResponse { $p = DB::table('payments')->where('id', $payment)->first(); - abort_if(! $p, 404, 'Payment not found.'); + abort_if(!$p, 404, 'Payment not found.'); $receipt = $this->service->nextReceiptNumber($p->school_year ?? date('Y')); $log = $this->service->log([ 'parent_id' => $p->parent_id ?? null, @@ -25,39 +25,34 @@ class FinanceNotificationController extends Controller 'notification_type' => 'payment_receipt', 'channel' => 'database', 'recipient' => (string) ($p->parent_id ?? ''), - 'subject' => 'Payment receipt '.$receipt, + 'subject' => 'Payment receipt ' . $receipt, ], optional($request->user())->id); - return response()->json(['ok' => true, 'receipt_number' => $receipt, 'notification_log' => $log]); } public function sendRefundReceipt(Request $request, int $refund): JsonResponse { $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]); } public function sendInvoiceStatement(Request $request, int $invoice): JsonResponse { $inv = DB::table('invoices')->where('id', $invoice)->first(); - abort_if(! $inv, 404, 'Invoice not found.'); + 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); - return response()->json(['ok' => true, 'notification_log' => $log]); } public function sendOverdueReminder(Request $request, int $parent): JsonResponse { $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]); } public function sendInstallmentReminder(Request $request, int $installment): JsonResponse { $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]); } diff --git a/app/Http/Controllers/Api/Finance/FinancialController.php b/app/Http/Controllers/Api/Finance/FinancialController.php index ba354af4..a78c8e36 100644 --- a/app/Http/Controllers/Api/Finance/FinancialController.php +++ b/app/Http/Controllers/Api/Finance/FinancialController.php @@ -5,10 +5,10 @@ namespace App\Http\Controllers\Api\Finance; use App\Http\Controllers\Api\Core\BaseApiController; use App\Http\Requests\Finance\FinancialReportRequest; use App\Http\Requests\Finance\FinancialSummaryRequest; -use App\Http\Requests\Finance\FinancialUnpaidParentsRequest; -use App\Http\Requests\Finance\FollowUpNoteRequest; -use App\Http\Requests\Finance\ParentPaymentFollowUpRequest; use App\Http\Requests\Finance\StakeholderFinancialAnalysisRequest; +use App\Http\Requests\Finance\FinancialUnpaidParentsRequest; +use App\Http\Requests\Finance\ParentPaymentFollowUpRequest; +use App\Http\Requests\Finance\FollowUpNoteRequest; use App\Http\Resources\Finance\FinancialReportResource; use App\Http\Resources\Finance\FinancialSummaryResource; use App\Http\Resources\Finance\FinancialUnpaidParentResource; @@ -16,9 +16,9 @@ use App\Services\Finance\FinancialPdfReportService; use App\Services\Finance\FinancialReportService; use App\Services\Finance\FinancialSchoolYearService; use App\Services\Finance\FinancialSummaryService; +use App\Services\Finance\StakeholderFinancialAnalysisService; use App\Services\Finance\FinancialUnpaidParentsService; use App\Services\Finance\ParentPaymentFollowUpService; -use App\Services\Finance\StakeholderFinancialAnalysisService; use Illuminate\Http\JsonResponse; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -82,6 +82,9 @@ class FinancialController extends BaseApiController ]); } + + + public function parentPaymentFollowups(ParentPaymentFollowUpRequest $request): JsonResponse { return response()->json([ @@ -101,7 +104,7 @@ class FinancialController extends BaseApiController fputcsv($out, $row); } fclose($out); - }, 'parent_payment_followups_'.($report['schoolYear'] ?? 'report').'_'.date('Ymd_His').'.csv', ['Content-Type' => 'text/csv']); + }, 'parent_payment_followups_' . ($report['schoolYear'] ?? 'report') . '_' . date('Ymd_His') . '.csv', ['Content-Type' => 'text/csv']); } public function storeParentFollowUpNote(FollowUpNoteRequest $request, int $parent): JsonResponse @@ -115,21 +118,18 @@ class FinancialController extends BaseApiController public function markParentContacted(FollowUpNoteRequest $request, int $parent): JsonResponse { $payload = array_merge($request->validated(), ['status' => $request->input('status', 'contacted')]); - return response()->json(['ok' => true, 'note' => $this->parentPaymentFollowUpService->storeNote($parent, $payload, optional($request->user())->id)], 201); } public function storePromiseToPay(FollowUpNoteRequest $request, int $parent): JsonResponse { $payload = array_merge($request->validated(), ['status' => 'promise_to_pay']); - return response()->json(['ok' => true, 'note' => $this->parentPaymentFollowUpService->storeNote($parent, $payload, optional($request->user())->id)], 201); } public function resolveParentFollowUp(FollowUpNoteRequest $request, int $parent): JsonResponse { $payload = array_merge($request->validated(), ['status' => 'resolved']); - return response()->json(['ok' => true, 'note' => $this->parentPaymentFollowUpService->storeNote($parent, $payload, optional($request->user())->id)], 201); } @@ -168,7 +168,7 @@ class FinancialController extends BaseApiController fputcsv($out, $row); } fclose($out); - }, 'stakeholder_financial_analysis_'.$schoolYear.'_'.date('Ymd_His').'.csv', ['Content-Type' => 'text/csv']); + }, 'stakeholder_financial_analysis_' . $schoolYear . '_' . date('Ymd_His') . '.csv', ['Content-Type' => 'text/csv']); } public function downloadCsv(FinancialReportRequest $request): StreamedResponse @@ -200,7 +200,7 @@ class FinancialController extends BaseApiController $breakdown = $report['paymentBreakdown'] ?? []; - $filename = 'financial_report_'.date('Ymd_His').'.csv'; + $filename = 'financial_report_' . date('Ymd_His') . '.csv'; return response()->streamDownload(function () use ($report, $paymentsMap, $refundsMap, $discountsMap, $breakdown) { $out = fopen('php://output', 'w'); @@ -309,6 +309,6 @@ class FinancialController extends BaseApiController return response()->streamDownload(function () use ($pdfBytes) { echo $pdfBytes; - }, 'Financial_Report_'.$schoolYear.'.pdf', ['Content-Type' => 'application/pdf']); + }, 'Financial_Report_' . $schoolYear . '.pdf', ['Content-Type' => 'application/pdf']); } } diff --git a/app/Http/Controllers/Api/Finance/InstallmentPlanController.php b/app/Http/Controllers/Api/Finance/InstallmentPlanController.php index 98e44832..796c66e5 100644 --- a/app/Http/Controllers/Api/Finance/InstallmentPlanController.php +++ b/app/Http/Controllers/Api/Finance/InstallmentPlanController.php @@ -13,52 +13,17 @@ class InstallmentPlanController extends Controller { public function __construct(private InstallmentPlanService $service) {} - public function index(Request $request): JsonResponse - { - return response()->json(['ok' => true, 'plans' => $this->service->list($request->query())]); - } - - public function store(InstallmentPlanRequest $request, int $invoice): JsonResponse - { - return response()->json(['ok' => true, 'plan' => $this->service->createForInvoice($invoice, $request->validated(), optional($request->user())->id)], 201); - } - - public function show(int $plan): JsonResponse - { - return response()->json(['ok' => true, 'plan' => $this->service->show($plan)]); - } - - public function activate(Request $request, int $plan): JsonResponse - { - return response()->json(['ok' => true, 'plan' => $this->service->activate($plan, optional($request->user())->id)]); - } - - public function cancel(int $plan): JsonResponse - { - return response()->json(['ok' => true, 'plan' => $this->service->cancel($plan)]); - } - + public function index(Request $request): JsonResponse { return response()->json(['ok' => true, 'plans' => $this->service->list($request->query())]); } + public function store(InstallmentPlanRequest $request, int $invoice): JsonResponse { return response()->json(['ok' => true, 'plan' => $this->service->createForInvoice($invoice, $request->validated(), optional($request->user())->id)], 201); } + public function show(int $plan): JsonResponse { return response()->json(['ok' => true, 'plan' => $this->service->show($plan)]); } + public function activate(Request $request, int $plan): JsonResponse { return response()->json(['ok' => true, 'plan' => $this->service->activate($plan, optional($request->user())->id)]); } + public function cancel(int $plan): JsonResponse { return response()->json(['ok' => true, 'plan' => $this->service->cancel($plan)]); } public function restructure(InstallmentPlanRequest $request, int $plan): JsonResponse { $old = $this->service->cancel($plan); - return response()->json(['ok' => true, 'old_plan' => $old, 'message' => 'Old plan cancelled. Create a replacement plan against the invoice to preserve audit history.']); } - - public function allocatePayment(PaymentAllocationRequest $request, int $payment): JsonResponse - { - return response()->json(['ok' => true, 'result' => $this->service->allocatePayment($payment, $request->validated())]); - } - - public function due(): JsonResponse - { - return response()->json(['ok' => true, 'installments' => $this->service->due(false)]); - } - - public function overdue(): JsonResponse - { - $this->service->markOverdue(); - - return response()->json(['ok' => true, 'installments' => $this->service->due(true)]); - } + public function allocatePayment(PaymentAllocationRequest $request, int $payment): JsonResponse { return response()->json(['ok' => true, 'result' => $this->service->allocatePayment($payment, $request->validated())]); } + public function due(): JsonResponse { return response()->json(['ok' => true, 'installments' => $this->service->due(false)]); } + public function overdue(): JsonResponse { $this->service->markOverdue(); return response()->json(['ok' => true, 'installments' => $this->service->due(true)]); } } diff --git a/app/Http/Controllers/Api/Finance/InvoiceController.php b/app/Http/Controllers/Api/Finance/InvoiceController.php index 0a2dc585..153ba53a 100644 --- a/app/Http/Controllers/Api/Finance/InvoiceController.php +++ b/app/Http/Controllers/Api/Finance/InvoiceController.php @@ -111,7 +111,7 @@ class InvoiceController extends BaseApiController $status = $request->validated()['status']; $updated = Invoice::updateInvoiceStatus($invoiceId, $status); - if (! $updated) { + if (!$updated) { return response()->json(['ok' => false, 'message' => 'Invoice not found.'], 404); } @@ -151,9 +151,12 @@ class InvoiceController extends BaseApiController return response()->streamDownload(function () use ($pdfBytes) { echo $pdfBytes; - }, 'invoice_'.$invoiceId.'.pdf', ['Content-Type' => 'application/pdf']); + }, 'invoice_' . $invoiceId . '.pdf', ['Content-Type' => 'application/pdf']); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Finance/PaymentController.php b/app/Http/Controllers/Api/Finance/PaymentController.php index 100e6462..db5c5477 100644 --- a/app/Http/Controllers/Api/Finance/PaymentController.php +++ b/app/Http/Controllers/Api/Finance/PaymentController.php @@ -82,7 +82,7 @@ class PaymentController extends BaseApiController $payload = $validator->validated(); $updated = $this->balanceService->updateBalance($paymentId, (float) $payload['paid_amount']); - if (! $updated) { + if (!$updated) { return response()->json(['ok' => false, 'message' => 'Payment not found.'], 404); } diff --git a/app/Http/Controllers/Api/Finance/PaymentEventChargesController.php b/app/Http/Controllers/Api/Finance/PaymentEventChargesController.php index bc8dc02f..5eeff71e 100644 --- a/app/Http/Controllers/Api/Finance/PaymentEventChargesController.php +++ b/app/Http/Controllers/Api/Finance/PaymentEventChargesController.php @@ -69,6 +69,9 @@ class PaymentEventChargesController extends BaseApiController return response()->json(['ok' => true, 'students' => $students]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Finance/PaymentManualController.php b/app/Http/Controllers/Api/Finance/PaymentManualController.php index 3f63440c..baa1a4fa 100644 --- a/app/Http/Controllers/Api/Finance/PaymentManualController.php +++ b/app/Http/Controllers/Api/Finance/PaymentManualController.php @@ -9,6 +9,7 @@ use App\Services\Payments\PaymentManualService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Facades\Log; class PaymentManualController extends BaseApiController { @@ -70,18 +71,25 @@ class PaymentManualController extends BaseApiController $payload = $request->validated(); - $result = $this->service->recordPayment( - $invoiceId, - (float) $payload['amount'], - (string) $payload['payment_method'], - $payload['payment_date'] ?? null, - $payload['check_number'] ?? null, - $payload['payment_type'] ?? null, - $request->file('payment_file'), - $payload['school_year'] ?? null, - $payload['semester'] ?? null, - $guard - ); + try { + $result = $this->service->recordPayment( + $invoiceId, + (float) $payload['amount'], + (string) $payload['payment_method'], + $payload['payment_date'] ?? null, + $payload['check_number'] ?? null, + $payload['payment_type'] ?? null, + $request->file('payment_file'), + $payload['school_year'] ?? null, + $payload['semester'] ?? null, + $guard + ); + } catch (\InvalidArgumentException $e) { + return response()->json(['ok' => false, 'message' => $e->getMessage()], 422); + } catch (\Throwable $e) { + Log::error('Manual payment record failed: ' . $e->getMessage()); + return response()->json(['ok' => false, 'message' => 'Unable to record payment.'], 400); + } return response()->json(['ok' => true] + $result); } @@ -95,14 +103,21 @@ class PaymentManualController extends BaseApiController $payload = $request->validated(); - $this->service->editPayment( - $paymentId, - (float) $payload['paid_amount'], - (string) $payload['payment_method'], - $payload['check_number'] ?? null, - $request->file('payment_file'), - $guard - ); + try { + $this->service->editPayment( + $paymentId, + (float) $payload['paid_amount'], + (string) $payload['payment_method'], + $payload['check_number'] ?? null, + $request->file('payment_file'), + $guard + ); + } catch (\InvalidArgumentException $e) { + return response()->json(['ok' => false, 'message' => $e->getMessage()], 422); + } catch (\Throwable $e) { + Log::error('Manual payment edit failed: ' . $e->getMessage()); + return response()->json(['ok' => false, 'message' => 'Unable to update payment.'], 400); + } return response()->json(['ok' => true]); } @@ -110,10 +125,12 @@ class PaymentManualController extends BaseApiController public function file(Request $request, string $filename) { $mode = (string) ($request->query('mode') ?? 'download'); - return $this->service->serveCheckFile($filename, $mode); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Finance/PaymentTransactionController.php b/app/Http/Controllers/Api/Finance/PaymentTransactionController.php index 25ff846b..f52645a1 100644 --- a/app/Http/Controllers/Api/Finance/PaymentTransactionController.php +++ b/app/Http/Controllers/Api/Finance/PaymentTransactionController.php @@ -83,7 +83,7 @@ class PaymentTransactionController extends BaseApiController $updated = $this->service->updateStatus($transactionId, (string) $status); - if (! $updated) { + if (!$updated) { return response()->json(['ok' => false, 'message' => 'Transaction not found.'], 404); } diff --git a/app/Http/Controllers/Api/Finance/PaypalTransactionsController.php b/app/Http/Controllers/Api/Finance/PaypalTransactionsController.php index f9bdf486..d6a75e3b 100644 --- a/app/Http/Controllers/Api/Finance/PaypalTransactionsController.php +++ b/app/Http/Controllers/Api/Finance/PaypalTransactionsController.php @@ -39,7 +39,7 @@ class PaypalTransactionsController extends BaseApiController $payload = $request->validated(); $rows = $this->service->listAll($payload['q'] ?? null); - $filename = 'paypal_transactions_'.date('Ymd_His').'.csv'; + $filename = 'paypal_transactions_' . date('Ymd_His') . '.csv'; return response()->streamDownload(function () use ($rows) { $out = fopen('php://output', 'w'); diff --git a/app/Http/Controllers/Api/Finance/PurchaseOrderController.php b/app/Http/Controllers/Api/Finance/PurchaseOrderController.php index e8ef46b9..7be4dd29 100644 --- a/app/Http/Controllers/Api/Finance/PurchaseOrderController.php +++ b/app/Http/Controllers/Api/Finance/PurchaseOrderController.php @@ -52,7 +52,7 @@ class PurchaseOrderController extends BaseApiController public function show(int $id): JsonResponse { $data = $this->queryService->find($id); - if (! $data) { + if (!$data) { return response()->json(['ok' => false, 'message' => 'Purchase order not found.'], 404); } @@ -69,7 +69,7 @@ class PurchaseOrderController extends BaseApiController $validator = Validator::make($data, [ 'po_number' => ['required', 'string', 'max:60'], 'supplier_id' => ['required', 'integer', 'min:1', 'exists:suppliers,id'], - 'status' => ['nullable', 'string', 'in:'.implode(',', PurchaseOrder::allowedStatuses())], + 'status' => ['nullable', 'string', 'in:' . implode(',', PurchaseOrder::allowedStatuses())], 'order_date' => ['nullable', 'date'], 'expected_date' => ['nullable', 'date'], 'notes' => ['nullable', 'string', 'max:5000'], @@ -88,7 +88,7 @@ class PurchaseOrderController extends BaseApiController } $payload = $validator->validated(); - if (! empty($payload['order_date']) && ! empty($payload['expected_date'])) { + if (!empty($payload['order_date']) && !empty($payload['expected_date'])) { $orderTs = strtotime((string) $payload['order_date']); $expectedTs = strtotime((string) $payload['expected_date']); if ($orderTs !== false && $expectedTs !== false && $expectedTs < $orderTs) { @@ -136,7 +136,7 @@ class PurchaseOrderController extends BaseApiController $payload = $validator->validated(); $po = PurchaseOrder::query()->find($id); - if (! $po) { + if (!$po) { return response()->json(['ok' => false, 'message' => 'Purchase order not found.'], 404); } @@ -169,7 +169,7 @@ class PurchaseOrderController extends BaseApiController } $po = PurchaseOrder::query()->find($id); - if (! $po) { + if (!$po) { return response()->json(['ok' => false, 'message' => 'Purchase order not found.'], 404); } diff --git a/app/Http/Controllers/Api/Finance/RefundController.php b/app/Http/Controllers/Api/Finance/RefundController.php index 76ffbbf2..6c503880 100644 --- a/app/Http/Controllers/Api/Finance/RefundController.php +++ b/app/Http/Controllers/Api/Finance/RefundController.php @@ -48,7 +48,7 @@ class RefundController extends BaseApiController public function show(int $refundId): JsonResponse { $refund = $this->queryService->find($refundId); - if (! $refund) { + if (!$refund) { return response()->json(['ok' => false, 'message' => 'Refund not found.'], 404); } @@ -71,7 +71,6 @@ class RefundController extends BaseApiController $result = $this->requestService->requestRefund($payload, $guard); } catch (\Throwable $e) { Log::error('Refund request failed.', ['error' => $e->getMessage()]); - return response()->json(['ok' => false, 'message' => 'Failed to submit refund request.'], 500); } @@ -213,6 +212,9 @@ class RefundController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Finance/ReimbursementController.php b/app/Http/Controllers/Api/Finance/ReimbursementController.php index f343854d..114b9fdb 100644 --- a/app/Http/Controllers/Api/Finance/ReimbursementController.php +++ b/app/Http/Controllers/Api/Finance/ReimbursementController.php @@ -93,7 +93,6 @@ class ReimbursementController extends BaseApiController } catch (RuntimeException $e) { $message = $e->getMessage(); $status = str_contains($message, 'not found') ? 404 : (str_contains($message, 'already') ? 409 : 422); - return response()->json(['ok' => false, 'message' => $message], $status); } catch (\Throwable $e) { return response()->json(['ok' => false, 'message' => 'Unable to mark donation right now.'], 500); @@ -145,7 +144,7 @@ class ReimbursementController extends BaseApiController $adminIdRaw = $payload['admin_id'] ?? null; $adminId = ($adminIdRaw === '' || $adminIdRaw === null) ? null : (int) $adminIdRaw; - $reimbursementId = ! empty($payload['reimbursement_id']) ? (int) $payload['reimbursement_id'] : null; + $reimbursementId = !empty($payload['reimbursement_id']) ? (int) $payload['reimbursement_id'] : null; try { $result = $this->assignmentService->updateAssignment( @@ -185,7 +184,6 @@ class ReimbursementController extends BaseApiController } catch (RuntimeException $e) { $message = $e->getMessage(); $status = str_contains($message, 'check file') ? 409 : 404; - return response()->json(['ok' => false, 'message' => $message], $status); } catch (\Throwable $e) { return response()->json(['ok' => false, 'message' => 'Unable to lock batch right now.'], 500); @@ -206,7 +204,7 @@ class ReimbursementController extends BaseApiController $adminId = (int) $payload['admin_id']; $batch = ReimbursementBatch::query()->find($batchId); - if (! $batch) { + if (!$batch) { return response()->json(['ok' => false, 'message' => 'Batch not found.'], 404); } if (strtolower((string) ($batch->status ?? '')) !== ReimbursementBatch::STATUS_OPEN) { @@ -233,7 +231,7 @@ class ReimbursementController extends BaseApiController return response(file_get_contents($meta['path']), 200, [ 'Content-Type' => $meta['mime'], - 'Content-Disposition' => $disposition.'; filename="'.$meta['download_name'].'"', + 'Content-Disposition' => $disposition . '; filename="' . $meta['download_name'] . '"', 'Content-Length' => (string) $meta['size'], 'ETag' => $meta['etag'], 'Last-Modified' => $meta['last_modified'], @@ -283,7 +281,7 @@ class ReimbursementController extends BaseApiController return response()->json(['ok' => false, 'message' => $e->getMessage()], 404); } - if (! $ok) { + if (!$ok) { return response()->json(['ok' => false, 'message' => 'Failed to send email. Please try again.'], 500); } @@ -303,7 +301,7 @@ class ReimbursementController extends BaseApiController return response()->streamDownload(function () use ($csv) { $out = fopen('php://output', 'w'); - fprintf($out, chr(0xEF).chr(0xBB).chr(0xBF)); + fprintf($out, chr(0xEF) . chr(0xBB) . chr(0xBF)); foreach ($csv['rows'] as $row) { fputcsv($out, $row); } @@ -320,7 +318,7 @@ class ReimbursementController extends BaseApiController return response()->streamDownload(function () use ($csv) { $out = fopen('php://output', 'w'); - fprintf($out, chr(0xEF).chr(0xBB).chr(0xBF)); + fprintf($out, chr(0xEF) . chr(0xBB) . chr(0xBF)); foreach ($csv['rows'] as $row) { fputcsv($out, $row); } @@ -438,7 +436,7 @@ class ReimbursementController extends BaseApiController } $reimb = Reimbursement::query()->find($id); - if (! $reimb) { + if (!$reimb) { return response()->json(['ok' => false, 'message' => 'Reimbursement not found.'], 404); } @@ -466,7 +464,7 @@ class ReimbursementController extends BaseApiController if ($request->hasFile('receipt')) { $receiptName = $this->fileService->storeReceipt($request->file('receipt')); } - if (! empty($payload['remove_receipt'])) { + if (!empty($payload['remove_receipt'])) { $receiptName = null; } @@ -480,6 +478,9 @@ class ReimbursementController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Frontend/FrontendController.php b/app/Http/Controllers/Api/Frontend/FrontendController.php index 12977b61..95664035 100644 --- a/app/Http/Controllers/Api/Frontend/FrontendController.php +++ b/app/Http/Controllers/Api/Frontend/FrontendController.php @@ -61,7 +61,7 @@ class FrontendController extends BaseApiController public function fetchUser(): JsonResponse { $user = auth()->user(); - if (! $user) { + if (!$user) { return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED); } diff --git a/app/Http/Controllers/Api/Frontend/InfoIconController.php b/app/Http/Controllers/Api/Frontend/InfoIconController.php index c6649574..150dcdda 100644 --- a/app/Http/Controllers/Api/Frontend/InfoIconController.php +++ b/app/Http/Controllers/Api/Frontend/InfoIconController.php @@ -29,6 +29,9 @@ class InfoIconController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Frontend/LandingPageController.php b/app/Http/Controllers/Api/Frontend/LandingPageController.php index 5e019a68..cc792f02 100644 --- a/app/Http/Controllers/Api/Frontend/LandingPageController.php +++ b/app/Http/Controllers/Api/Frontend/LandingPageController.php @@ -19,7 +19,7 @@ class LandingPageController extends BaseApiController public function index(LandingTeacherRequest $request): JsonResponse { $user = $request->user(); - if (! $user) { + if (!$user) { return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED); } @@ -36,7 +36,7 @@ class LandingPageController extends BaseApiController public function teacher(LandingTeacherRequest $request): JsonResponse { $user = $request->user(); - if (! $user) { + if (!$user) { return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED); } @@ -53,7 +53,7 @@ class LandingPageController extends BaseApiController public function parent(): JsonResponse { $user = auth()->user(); - if (! $user) { + if (!$user) { return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED); } diff --git a/app/Http/Controllers/Api/Frontend/PageController.php b/app/Http/Controllers/Api/Frontend/PageController.php index 2beeb093..0aefcccf 100644 --- a/app/Http/Controllers/Api/Frontend/PageController.php +++ b/app/Http/Controllers/Api/Frontend/PageController.php @@ -51,7 +51,7 @@ class PageController extends BaseApiController private function renderStatic(string $filename, string $type): JsonResponse { $result = $this->pageService->load($filename, $type); - if (! $result['ok']) { + if (!$result['ok']) { return $this->error($result['error'], Response::HTTP_NOT_FOUND); } diff --git a/app/Http/Controllers/Api/Grading/GradingController.php b/app/Http/Controllers/Api/Grading/GradingController.php index 312f0985..869ab0d2 100644 --- a/app/Http/Controllers/Api/Grading/GradingController.php +++ b/app/Http/Controllers/Api/Grading/GradingController.php @@ -3,17 +3,17 @@ namespace App\Http\Controllers\Api\Grading; use App\Http\Controllers\Api\Core\BaseApiController; +use App\Http\Requests\Grading\BelowSixtyEmailRequest; use App\Http\Requests\Grading\AllDecisionsRequest; use App\Http\Requests\Grading\BelowSixtyDecisionDetailsRequest; use App\Http\Requests\Grading\BelowSixtyDecisionListRequest; use App\Http\Requests\Grading\BelowSixtyDecisionSaveRequest; use App\Http\Requests\Grading\BelowSixtyDecisionSendRequest; -use App\Http\Requests\Grading\BelowSixtyEmailRequest; -use App\Http\Requests\Grading\BelowSixtyListRequest; use App\Http\Requests\Grading\BelowSixtyMeetingRequest; use App\Http\Requests\Grading\BelowSixtyMeetingSaveRequest; use App\Http\Requests\Grading\BelowSixtySendRequest; use App\Http\Requests\Grading\BelowSixtyStatusRequest; +use App\Http\Requests\Grading\BelowSixtyListRequest; use App\Http\Requests\Grading\GenerateAllDecisionsRequest; use App\Http\Requests\Grading\GradingLockAllRequest; use App\Http\Requests\Grading\GradingLockRequest; @@ -23,8 +23,8 @@ use App\Http\Requests\Grading\GradingScoreShowRequest; use App\Http\Requests\Grading\GradingScoreUpdateRequest; use App\Http\Requests\Grading\PlacementBatchRequest; use App\Http\Requests\Grading\PlacementBatchUpdateRequest; -use App\Http\Requests\Grading\PlacementLevelRequest; use App\Http\Requests\Grading\PlacementLevelsRequest; +use App\Http\Requests\Grading\PlacementLevelRequest; use App\Http\Requests\Grading\PlacementRequest; use App\Http\Resources\Grading\BelowSixtyStudentResource; use App\Http\Resources\Grading\GradingScoreResource; @@ -419,6 +419,9 @@ class GradingController extends BaseApiController return response()->json(['ok' => true]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Incidents/IncidentController.php b/app/Http/Controllers/Api/Incidents/IncidentController.php index b74dfedc..e2849d2d 100644 --- a/app/Http/Controllers/Api/Incidents/IncidentController.php +++ b/app/Http/Controllers/Api/Incidents/IncidentController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api\Incidents; use App\Http\Controllers\Api\Core\BaseApiController; use App\Http\Requests\Incidents\IncidentCancelRequest; +use App\Http\Requests\Incidents\IncidentCloseRequest; use App\Http\Requests\Incidents\IncidentListRequest; use App\Http\Requests\Incidents\IncidentStateRequest; use App\Http\Resources\Incidents\IncidentAnalysisStudentResource; @@ -208,6 +209,9 @@ class IncidentController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Inventory/InventoryCategoryController.php b/app/Http/Controllers/Api/Inventory/InventoryCategoryController.php index 6f54b921..39501c5c 100644 --- a/app/Http/Controllers/Api/Inventory/InventoryCategoryController.php +++ b/app/Http/Controllers/Api/Inventory/InventoryCategoryController.php @@ -31,7 +31,7 @@ class InventoryCategoryController extends BaseApiController public function store(InventoryCategoryStoreRequest $request): JsonResponse { $result = $this->categories->create($request->validated()); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to save category.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -46,7 +46,7 @@ class InventoryCategoryController extends BaseApiController return $this->error($e->getMessage(), Response::HTTP_UNPROCESSABLE_ENTITY); } - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to update category.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -56,7 +56,7 @@ class InventoryCategoryController extends BaseApiController public function destroy(int $id): JsonResponse { $result = $this->categories->delete($id); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to delete category.', Response::HTTP_UNPROCESSABLE_ENTITY); } diff --git a/app/Http/Controllers/Api/Inventory/InventoryController.php b/app/Http/Controllers/Api/Inventory/InventoryController.php index b2c9214c..669ea5dd 100644 --- a/app/Http/Controllers/Api/Inventory/InventoryController.php +++ b/app/Http/Controllers/Api/Inventory/InventoryController.php @@ -48,7 +48,7 @@ class InventoryController extends BaseApiController public function show(int $id): JsonResponse { $item = $this->items->find($id); - if (! $item) { + if (!$item) { return $this->error('Item not found.', Response::HTTP_NOT_FOUND); } @@ -63,7 +63,7 @@ class InventoryController extends BaseApiController } $result = $this->items->create($request->validated(), $actor); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to create item.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -78,7 +78,7 @@ class InventoryController extends BaseApiController } $result = $this->items->update($id, $request->validated(), $actor); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to update item.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -88,7 +88,7 @@ class InventoryController extends BaseApiController public function destroy(int $id): JsonResponse { $result = $this->items->delete($id); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to delete item.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -103,7 +103,7 @@ class InventoryController extends BaseApiController } $result = $this->items->auditClassroom($id, $request->validated(), $actor); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to audit item.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -118,7 +118,7 @@ class InventoryController extends BaseApiController } $result = $this->items->adjustStock($id, $request->validated(), $actor); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to adjust stock.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -128,7 +128,6 @@ class InventoryController extends BaseApiController public function summary(string $type): JsonResponse { $payload = $this->summary->summary($type, request()->query('school_year')); - return $this->success($payload); } @@ -138,7 +137,6 @@ class InventoryController extends BaseApiController request()->query('school_year'), request()->query('type') ); - return $this->success($payload); } @@ -156,7 +154,7 @@ class InventoryController extends BaseApiController $payload['item_id'] ?? null ); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Unable to load distribution form.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -173,18 +171,20 @@ class InventoryController extends BaseApiController try { $result = $this->distribution->distribute($actor, $request->validated()); } catch (\Throwable $e) { - Log::error('Inventory distribution failed: '.$e->getMessage()); - + Log::error('Inventory distribution failed: ' . $e->getMessage()); return $this->error('Unable to distribute inventory.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Unable to distribute inventory.', Response::HTTP_UNPROCESSABLE_ENTITY); } return $this->success($result); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Inventory/InventoryMovementController.php b/app/Http/Controllers/Api/Inventory/InventoryMovementController.php index 6b86aa91..6e18cf08 100644 --- a/app/Http/Controllers/Api/Inventory/InventoryMovementController.php +++ b/app/Http/Controllers/Api/Inventory/InventoryMovementController.php @@ -36,7 +36,7 @@ class InventoryMovementController extends BaseApiController } $result = $this->movements->create($request->validated(), $actor); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to create movement.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -46,7 +46,7 @@ class InventoryMovementController extends BaseApiController public function update(InventoryMovementUpdateRequest $request, int $id): JsonResponse { $result = $this->movements->update($id, $request->validated()); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to update movement.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -56,7 +56,7 @@ class InventoryMovementController extends BaseApiController public function destroy(int $id): JsonResponse { $result = $this->movements->delete($id); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to delete movement.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -66,13 +66,16 @@ class InventoryMovementController extends BaseApiController public function bulkDelete(InventoryMovementBulkDeleteRequest $request): JsonResponse { $result = $this->movements->bulkDelete($request->validated()['ids']); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Bulk delete failed.', Response::HTTP_UNPROCESSABLE_ENTITY); } return $this->success($result); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Inventory/SupplierController.php b/app/Http/Controllers/Api/Inventory/SupplierController.php index c64c9061..509488a9 100644 --- a/app/Http/Controllers/Api/Inventory/SupplierController.php +++ b/app/Http/Controllers/Api/Inventory/SupplierController.php @@ -33,7 +33,7 @@ class SupplierController extends BaseApiController public function store(SupplierStoreRequest $request): JsonResponse { $result = $this->suppliers->create($request->validated()); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to save supplier.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -43,7 +43,7 @@ class SupplierController extends BaseApiController public function update(SupplierUpdateRequest $request, int $id): JsonResponse { $result = $this->suppliers->update($id, $request->validated()); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to update supplier.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -53,7 +53,7 @@ class SupplierController extends BaseApiController public function destroy(int $id): JsonResponse { $result = $this->suppliers->delete($id); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to delete supplier.', Response::HTTP_UNPROCESSABLE_ENTITY); } diff --git a/app/Http/Controllers/Api/Inventory/SupplyCategoryController.php b/app/Http/Controllers/Api/Inventory/SupplyCategoryController.php index 25a5bc87..4a0b0e89 100644 --- a/app/Http/Controllers/Api/Inventory/SupplyCategoryController.php +++ b/app/Http/Controllers/Api/Inventory/SupplyCategoryController.php @@ -29,7 +29,7 @@ class SupplyCategoryController extends BaseApiController public function store(SupplyCategoryStoreRequest $request): JsonResponse { $result = $this->categories->create($request->validated()); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to save category.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -39,7 +39,7 @@ class SupplyCategoryController extends BaseApiController public function update(SupplyCategoryUpdateRequest $request, int $id): JsonResponse { $result = $this->categories->update($id, $request->validated()); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to update category.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -49,7 +49,7 @@ class SupplyCategoryController extends BaseApiController public function destroy(int $id): JsonResponse { $result = $this->categories->delete($id); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to delete category.', Response::HTTP_UNPROCESSABLE_ENTITY); } diff --git a/app/Http/Controllers/Api/Messaging/MessagesController.php b/app/Http/Controllers/Api/Messaging/MessagesController.php index f6fffc8e..6f7374ee 100644 --- a/app/Http/Controllers/Api/Messaging/MessagesController.php +++ b/app/Http/Controllers/Api/Messaging/MessagesController.php @@ -75,7 +75,7 @@ class MessagesController extends BaseApiController public function show(int $id): JsonResponse { $message = $this->queryService->findForUser($id); - if (! $message) { + if (!$message) { return $this->error('Message not found.', Response::HTTP_NOT_FOUND); } @@ -104,8 +104,7 @@ class MessagesController extends BaseApiController try { $message = $this->commandService->create($guard, $request->validated(), $request->file('attachment')); } catch (\Throwable $e) { - Log::error('Message send failed: '.$e->getMessage()); - + Log::error('Message send failed: ' . $e->getMessage()); return $this->error($e->getMessage(), Response::HTTP_BAD_REQUEST); } @@ -151,7 +150,7 @@ class MessagesController extends BaseApiController public function update(MessageUpdateRequest $request, int $id): JsonResponse { $message = Message::query()->find($id); - if (! $message) { + if (!$message) { return $this->error('Message not found.', Response::HTTP_NOT_FOUND); } @@ -160,8 +159,7 @@ class MessagesController extends BaseApiController try { $updated = $this->commandService->update($message, $request->validated()); } catch (\Throwable $e) { - Log::error('Message update failed: '.$e->getMessage()); - + Log::error('Message update failed: ' . $e->getMessage()); return $this->error('Unable to update message.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -173,7 +171,7 @@ class MessagesController extends BaseApiController public function destroy(int $id): JsonResponse { $message = Message::query()->find($id); - if (! $message) { + if (!$message) { return $this->error('Message not found.', Response::HTTP_NOT_FOUND); } @@ -182,12 +180,11 @@ class MessagesController extends BaseApiController try { $trashed = $this->commandService->trash($message); } catch (\Throwable $e) { - Log::error('Message delete failed: '.$e->getMessage()); - + Log::error('Message delete failed: ' . $e->getMessage()); return $this->error('Unable to delete message.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! $trashed) { + if (!$trashed) { return $this->error('Unable to delete message.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -223,6 +220,9 @@ class MessagesController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Messaging/WhatsappController.php b/app/Http/Controllers/Api/Messaging/WhatsappController.php index 0a225c8d..a7d52d28 100644 --- a/app/Http/Controllers/Api/Messaging/WhatsappController.php +++ b/app/Http/Controllers/Api/Messaging/WhatsappController.php @@ -117,12 +117,11 @@ class WhatsappController extends BaseApiController try { $result = $this->inviteService->send($request->validated()); } catch (\Throwable $e) { - Log::error('WhatsApp invite send failed: '.$e->getMessage()); - + Log::error('WhatsApp invite send failed: ' . $e->getMessage()); return $this->error('Invite processing failed.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Invite processing failed.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -141,12 +140,11 @@ class WhatsappController extends BaseApiController try { $result = $this->membershipService->updateMembership($request->validated(), $userId); } catch (\Throwable $e) { - Log::error('WhatsApp membership update failed: '.$e->getMessage()); - + Log::error('WhatsApp membership update failed: ' . $e->getMessage()); return $this->error('Failed to save membership.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { $code = str_contains((string) ($result['message'] ?? ''), 'missing') ? Response::HTTP_INTERNAL_SERVER_ERROR : Response::HTTP_UNPROCESSABLE_ENTITY; @@ -160,6 +158,9 @@ class WhatsappController extends BaseApiController ], 'Membership saved.'); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Notifications/NotificationController.php b/app/Http/Controllers/Api/Notifications/NotificationController.php index aaa70ec8..f6e189c9 100644 --- a/app/Http/Controllers/Api/Notifications/NotificationController.php +++ b/app/Http/Controllers/Api/Notifications/NotificationController.php @@ -59,7 +59,7 @@ class NotificationController extends BaseApiController } $row = $this->showService->getForUser($guard, $notificationId); - if (! $row) { + if (!$row) { return response()->json(['ok' => false, 'message' => 'Notification not found.'], 404); } @@ -82,7 +82,6 @@ class NotificationController extends BaseApiController $result = $this->sendService->send($payload, $guard); } catch (\Throwable $e) { Log::error('Notification send failed.', ['error' => $e->getMessage()]); - return response()->json(['ok' => false, 'message' => 'Failed to send notification.'], 500); } @@ -115,7 +114,7 @@ class NotificationController extends BaseApiController public function destroy(int $notificationId): JsonResponse { $deleted = $this->managementService->delete($notificationId); - if (! $deleted) { + if (!$deleted) { return response()->json(['ok' => false, 'message' => 'Notification not found.'], 404); } @@ -125,7 +124,7 @@ class NotificationController extends BaseApiController public function restore(int $notificationId): JsonResponse { $restored = $this->managementService->restore($notificationId); - if (! $restored) { + if (!$restored) { return response()->json(['ok' => false, 'message' => 'Notification not found.'], 404); } @@ -140,7 +139,7 @@ class NotificationController extends BaseApiController } $ok = $this->readService->markRead($guard, $notificationId); - if (! $ok) { + if (!$ok) { return response()->json(['ok' => false, 'message' => 'Notification not found.'], 404); } @@ -168,6 +167,9 @@ class NotificationController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Parents/ParentAttendanceReportController.php b/app/Http/Controllers/Api/Parents/ParentAttendanceReportController.php index 0710ea7f..271ba93c 100644 --- a/app/Http/Controllers/Api/Parents/ParentAttendanceReportController.php +++ b/app/Http/Controllers/Api/Parents/ParentAttendanceReportController.php @@ -3,9 +3,9 @@ namespace App\Http\Controllers\Api\Parents; use App\Http\Controllers\Api\Core\BaseApiController; -use App\Http\Requests\Parents\ParentAttendanceReportCheckRequest; -use App\Http\Requests\Parents\ParentAttendanceReportListRequest; use App\Http\Requests\Parents\ParentAttendanceReportSubmitRequest; +use App\Http\Requests\Parents\ParentAttendanceReportListRequest; +use App\Http\Requests\Parents\ParentAttendanceReportCheckRequest; use App\Http\Requests\Parents\ParentAttendanceReportUpdateRequest; use App\Http\Resources\Parents\ParentAttendanceReportResource; use App\Services\Parents\ParentAttendanceReportService; @@ -116,6 +116,9 @@ class ParentAttendanceReportController extends BaseApiController return response()->json(['ok' => true]); } + /** + * @return int|JsonResponse + */ private function parentIdOrUnauthorized(): int|JsonResponse { $parentId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Parents/ParentController.php b/app/Http/Controllers/Api/Parents/ParentController.php index d1b0f2d8..1dd0f3b8 100644 --- a/app/Http/Controllers/Api/Parents/ParentController.php +++ b/app/Http/Controllers/Api/Parents/ParentController.php @@ -4,18 +4,18 @@ namespace App\Http\Controllers\Api\Parents; use App\Http\Controllers\Api\Core\BaseApiController; use App\Http\Requests\Parents\ParentAttendanceRequest; -use App\Http\Requests\Parents\ParentEmergencyContactRequest; use App\Http\Requests\Parents\ParentEnrollmentActionRequest; use App\Http\Requests\Parents\ParentEnrollmentRequest; +use App\Http\Requests\Parents\ParentEmergencyContactRequest; use App\Http\Requests\Parents\ParentEventParticipationRequest; use App\Http\Requests\Parents\ParentInvoiceRequest; use App\Http\Requests\Parents\ParentProfileUpdateRequest; use App\Http\Requests\Parents\ParentRegistrationRequest; use App\Http\Requests\Parents\ParentStudentUpdateRequest; -use App\Http\Resources\Invoices\InvoiceResource; use App\Http\Resources\Parents\ParentAttendanceResource; use App\Http\Resources\Parents\ParentEmergencyContactResource; use App\Http\Resources\Parents\ParentStudentResource; +use App\Http\Resources\Invoices\InvoiceResource; use App\Services\Parents\ParentAttendanceService; use App\Services\Parents\ParentEmergencyContactService; use App\Services\Parents\ParentEnrollmentService; diff --git a/app/Http/Controllers/Api/Parents/ParentPromotionController.php b/app/Http/Controllers/Api/Parents/ParentPromotionController.php index 24bb93fa..6b861b4a 100644 --- a/app/Http/Controllers/Api/Parents/ParentPromotionController.php +++ b/app/Http/Controllers/Api/Parents/ParentPromotionController.php @@ -140,21 +140,20 @@ class ParentPromotionController extends BaseApiController private function loadOwnedRecord(int $promotionId, int $parentId): StudentPromotionRecord|JsonResponse { $record = StudentPromotionRecord::query()->find($promotionId); - if (! $record) { + if (!$record) { return response()->json(['ok' => false, 'message' => 'Promotion record not found.'], Response::HTTP_NOT_FOUND); } $owns = (int) $record->parent_id === $parentId; - if (! $owns) { + if (!$owns) { $studentParentId = (int) (Student::query() ->where('id', $record->student_id) ->value('parent_id') ?? 0); $owns = $studentParentId === $parentId; } - if (! $owns) { + if (!$owns) { return response()->json(['ok' => false, 'message' => 'You are not authorised to view this promotion record.'], Response::HTTP_FORBIDDEN); } - return $record; } @@ -169,7 +168,6 @@ class ParentPromotionController extends BaseApiController if ($parentId <= 0) { return response()->json(['ok' => false, 'message' => 'Unauthorized.'], Response::HTTP_UNAUTHORIZED); } - return $parentId; } } diff --git a/app/Http/Controllers/Api/PrintRequests/PrintRequestsController.php b/app/Http/Controllers/Api/PrintRequests/PrintRequestsController.php index 8fce19e9..ca3ba992 100644 --- a/app/Http/Controllers/Api/PrintRequests/PrintRequestsController.php +++ b/app/Http/Controllers/Api/PrintRequests/PrintRequestsController.php @@ -8,7 +8,6 @@ use App\Models\User; use App\Services\PrintRequests\PrintRequestsPortalService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; @@ -60,7 +59,7 @@ class PrintRequestsController extends BaseApiController return $this->respondValidationError($validator->errors()->toArray()); } - /** @var UploadedFile $file */ + /** @var \Illuminate\Http\UploadedFile $file */ $file = $request->file('file'); $model = $this->portal->storeTeacherUpload($validator->validated(), $file, $uid); diff --git a/app/Http/Controllers/Api/Reports/ReportCardsController.php b/app/Http/Controllers/Api/Reports/ReportCardsController.php index d9145948..1fc98ea0 100644 --- a/app/Http/Controllers/Api/Reports/ReportCardsController.php +++ b/app/Http/Controllers/Api/Reports/ReportCardsController.php @@ -52,7 +52,7 @@ class ReportCardsController extends BaseApiController $classSectionId = (int) ($payload['class_section_id'] ?? 0); $result = $this->service->completeness($schoolYear, $semester, $classSectionId); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Unable to generate completeness report.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -101,12 +101,11 @@ class ReportCardsController extends BaseApiController try { $result = $this->service->generateSingleReport($studentId, $request->validated()); } catch (\Throwable $e) { - Log::error('Report card PDF generation failed: '.$e->getMessage()); - + Log::error('Report card PDF generation failed: ' . $e->getMessage()); return $this->error('Failed to generate report card.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Unable to generate report card.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -114,7 +113,7 @@ class ReportCardsController extends BaseApiController return response($result['pdf'], 200, [ 'Content-Type' => 'application/pdf', - 'Content-Disposition' => $disposition.'; filename="'.($result['filename'] ?? 'ReportCard.pdf').'"', + 'Content-Disposition' => $disposition . '; filename="' . ($result['filename'] ?? 'ReportCard.pdf') . '"', 'Cache-Control' => 'private, max-age=0, must-revalidate', 'Pragma' => 'public', ]); @@ -125,12 +124,11 @@ class ReportCardsController extends BaseApiController try { $result = $this->service->generateClassReport($classSectionId, $request->validated()); } catch (\Throwable $e) { - Log::error('Class report card PDF generation failed: '.$e->getMessage()); - + Log::error('Class report card PDF generation failed: ' . $e->getMessage()); return $this->error('Failed to generate class report cards.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Unable to generate class report cards.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -138,7 +136,7 @@ class ReportCardsController extends BaseApiController return response($result['pdf'], 200, [ 'Content-Type' => 'application/pdf', - 'Content-Disposition' => $disposition.'; filename="'.($result['filename'] ?? 'ClassReportCards.pdf').'"', + 'Content-Disposition' => $disposition . '; filename="' . ($result['filename'] ?? 'ClassReportCards.pdf') . '"', 'Cache-Control' => 'private, max-age=0, must-revalidate', 'Pragma' => 'public', ]); @@ -150,7 +148,6 @@ class ReportCardsController extends BaseApiController if ($value !== '') { return $value; } - return trim((string) (Configuration::getConfig('school_year') ?? '')); } @@ -160,7 +157,6 @@ class ReportCardsController extends BaseApiController if ($value !== '') { return $value; } - return trim((string) (Configuration::getConfig('semester') ?? '')); } } diff --git a/app/Http/Controllers/Api/Reports/SlipPrinterController.php b/app/Http/Controllers/Api/Reports/SlipPrinterController.php index b285b9f7..44b3685e 100644 --- a/app/Http/Controllers/Api/Reports/SlipPrinterController.php +++ b/app/Http/Controllers/Api/Reports/SlipPrinterController.php @@ -27,13 +27,13 @@ class SlipPrinterController extends BaseApiController $result = $this->service->print($request->validated(), $guard); - if (! $result['ok']) { + if (!$result['ok']) { return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Print failed.'], 422); } return response($result['pdf'], 200, [ 'Content-Type' => 'application/pdf', - 'Content-Disposition' => 'inline; filename="'.$result['filename'].'"', + 'Content-Disposition' => 'inline; filename="' . $result['filename'] . '"', ]); } @@ -78,16 +78,19 @@ class SlipPrinterController extends BaseApiController $result = $this->service->reprint((int) $request->validated()['id'], $guard); - if (! $result['ok']) { + if (!$result['ok']) { return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Slip not found.'], 404); } return response($result['pdf'], 200, [ 'Content-Type' => 'application/pdf', - 'Content-Disposition' => 'inline; filename="'.$result['filename'].'"', + 'Content-Disposition' => 'inline; filename="' . $result['filename'] . '"', ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Reports/StickersController.php b/app/Http/Controllers/Api/Reports/StickersController.php index 8cfa11d2..a5129532 100644 --- a/app/Http/Controllers/Api/Reports/StickersController.php +++ b/app/Http/Controllers/Api/Reports/StickersController.php @@ -64,18 +64,17 @@ class StickersController extends BaseApiController try { $result = $this->printService->generate($request->validated()); } catch (\Throwable $e) { - Log::error('Sticker print failed: '.$e->getMessage()); - + Log::error('Sticker print failed: ' . $e->getMessage()); return $this->error('Failed to generate stickers.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Unable to generate stickers.', Response::HTTP_UNPROCESSABLE_ENTITY); } return response($result['pdf'], 200, [ 'Content-Type' => 'application/pdf', - 'Content-Disposition' => 'inline; filename="'.($result['filename'] ?? 'Student_Stickers.pdf').'"', + 'Content-Disposition' => 'inline; filename="' . ($result['filename'] ?? 'Student_Stickers.pdf') . '"', ]); } } diff --git a/app/Http/Controllers/Api/RolePermissionController.php b/app/Http/Controllers/Api/RolePermissionController.php index 0013504e..4b331fd4 100644 --- a/app/Http/Controllers/Api/RolePermissionController.php +++ b/app/Http/Controllers/Api/RolePermissionController.php @@ -55,7 +55,7 @@ class RolePermissionController extends BaseApiController public function showRole(int $roleId): JsonResponse { $role = Role::query()->find($roleId); - if (! $role) { + if (!$role) { return $this->error('Role not found.', Response::HTTP_NOT_FOUND); } @@ -69,8 +69,7 @@ class RolePermissionController extends BaseApiController try { $role = $this->roleCrudService->create($request->validated()); } catch (\Throwable $e) { - Log::error('Role store failed: '.$e->getMessage()); - + Log::error('Role store failed: ' . $e->getMessage()); return $this->error('Failed to create role.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -82,15 +81,14 @@ class RolePermissionController extends BaseApiController public function updateRole(RoleUpdateRequest $request, int $roleId): JsonResponse { $role = Role::query()->find($roleId); - if (! $role) { + if (!$role) { return $this->error('Role not found.', Response::HTTP_NOT_FOUND); } try { $role = $this->roleCrudService->update($role, $request->validated()); } catch (\Throwable $e) { - Log::error('Role update failed: '.$e->getMessage()); - + Log::error('Role update failed: ' . $e->getMessage()); return $this->error('Failed to update role.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -102,15 +100,14 @@ class RolePermissionController extends BaseApiController public function deleteRole(int $roleId): JsonResponse { $role = Role::query()->find($roleId); - if (! $role) { + if (!$role) { return $this->error('Role not found.', Response::HTTP_NOT_FOUND); } try { $this->roleCrudService->delete($role); } catch (\Throwable $e) { - Log::error('Role delete failed: '.$e->getMessage()); - + Log::error('Role delete failed: ' . $e->getMessage()); return $this->error('Failed to delete role.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -141,12 +138,11 @@ class RolePermissionController extends BaseApiController (int) (auth()->id() ?? 0) ); } catch (\Throwable $e) { - Log::error('Assign roles failed: '.$e->getMessage()); - + Log::error('Assign roles failed: ' . $e->getMessage()); return $this->error('Failed to update roles.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Failed to update roles.', Response::HTTP_UNPROCESSABLE_ENTITY); } @@ -167,7 +163,7 @@ class RolePermissionController extends BaseApiController public function showPermission(int $permissionId): JsonResponse { $permission = Permission::query()->find($permissionId); - if (! $permission) { + if (!$permission) { return $this->error('Permission not found.', Response::HTTP_NOT_FOUND); } @@ -181,8 +177,7 @@ class RolePermissionController extends BaseApiController try { $permission = $this->permissionCrudService->create($request->validated()); } catch (\Throwable $e) { - Log::error('Permission store failed: '.$e->getMessage()); - + Log::error('Permission store failed: ' . $e->getMessage()); return $this->error('Failed to create permission.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -194,15 +189,14 @@ class RolePermissionController extends BaseApiController public function updatePermission(PermissionUpdateRequest $request, int $permissionId): JsonResponse { $permission = Permission::query()->find($permissionId); - if (! $permission) { + if (!$permission) { return $this->error('Permission not found.', Response::HTTP_NOT_FOUND); } try { $permission = $this->permissionCrudService->update($permission, $request->validated()); } catch (\Throwable $e) { - Log::error('Permission update failed: '.$e->getMessage()); - + Log::error('Permission update failed: ' . $e->getMessage()); return $this->error('Failed to update permission.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -214,15 +208,14 @@ class RolePermissionController extends BaseApiController public function deletePermission(int $permissionId): JsonResponse { $permission = Permission::query()->find($permissionId); - if (! $permission) { + if (!$permission) { return $this->error('Permission not found.', Response::HTTP_NOT_FOUND); } try { $this->permissionCrudService->delete($permission); } catch (\Throwable $e) { - Log::error('Permission delete failed: '.$e->getMessage()); - + Log::error('Permission delete failed: ' . $e->getMessage()); return $this->error('Failed to delete permission.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -243,8 +236,7 @@ class RolePermissionController extends BaseApiController try { $this->permissionService->saveRolePermissions($roleId, $request->validated()['permissions'] ?? []); } catch (\Throwable $e) { - Log::error('Role permissions update failed: '.$e->getMessage()); - + Log::error('Role permissions update failed: ' . $e->getMessage()); return $this->error('Failed to update role permissions.', Response::HTTP_INTERNAL_SERVER_ERROR); } diff --git a/app/Http/Controllers/Api/RoleSwitcherController.php b/app/Http/Controllers/Api/RoleSwitcherController.php index 0758dae3..2f22e748 100644 --- a/app/Http/Controllers/Api/RoleSwitcherController.php +++ b/app/Http/Controllers/Api/RoleSwitcherController.php @@ -5,9 +5,9 @@ namespace App\Http\Controllers\Api; use App\Http\Requests\Roles\RoleSwitchRequest; use App\Services\Roles\RoleSwitchService; use Illuminate\Http\JsonResponse; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpFoundation\Response; class RoleSwitcherController extends BaseApiController { diff --git a/app/Http/Controllers/Api/ScannerController.php b/app/Http/Controllers/Api/ScannerController.php index 26dde969..d8d3264d 100644 --- a/app/Http/Controllers/Api/ScannerController.php +++ b/app/Http/Controllers/Api/ScannerController.php @@ -23,13 +23,12 @@ use Illuminate\Support\Facades\Schema; class ScannerController extends BaseApiController { private const LATE_CUTOFF_CONFIG_KEY = 'attendance_late_cutoff_time'; - private const DEFAULT_LATE_CUTOFF = '10:00 AM'; public function process(Request $request): JsonResponse { $data = $request->json()->all(); - if (! is_array($data) || $data === []) { + if (!is_array($data) || $data === []) { $data = $request->all(); } @@ -42,11 +41,10 @@ class ScannerController extends BaseApiController if ($badgeCode === '') { $this->logScan($badgeCode, null, null, $action, 'rejected', $operatorId, $stationId, 'Badge code is required.', $scannedAt); - return response()->json($this->failure('Badge code is required.'), 400); } - if (! in_array($scanStatus, ['present', 'late'], true)) { + if (!in_array($scanStatus, ['present', 'late'], true)) { $scanStatus = 'present'; } @@ -61,7 +59,6 @@ class ScannerController extends BaseApiController } $this->logScan($badgeCode, null, null, $action, 'not_found', $operatorId, $stationId, 'Badge not found.', $scannedAt); - return response()->json($this->failure('Badge not found.'), 404); } @@ -77,9 +74,8 @@ class ScannerController extends BaseApiController } $assignment = $this->studentAssignment((int) $student->id, $term['semester'], $term['school_year']); - if (! $assignment) { + if (!$assignment) { $this->logScan($badgeCode, 'student', (int) $student->id, $action, 'rejected', $operatorId, $stationId, 'Student has no class assignment for current term.', $scannedAt); - return response()->json($this->failure('Student has no class assignment for current term.'), 409); } @@ -154,7 +150,7 @@ class ScannerController extends BaseApiController $operatorId, $existing ? (string) ($oldStatus ?? '') : null ); - $warnings[] = 'Student arrived after '.$lateCutoff->format('h:i A').'. Late slip receipt generated.'; + $warnings[] = 'Student arrived after ' . $lateCutoff->format('h:i A') . '. Late slip receipt generated.'; } return response()->json($this->successPayload([ @@ -198,7 +194,7 @@ class ScannerController extends BaseApiController $person = [ 'id' => (int) $user->id, - 'name' => trim((string) ($user->firstname ?? '').' '.(string) ($user->lastname ?? '')), + 'name' => trim((string) ($user->firstname ?? '') . ' ' . (string) ($user->lastname ?? '')), 'email' => $user->email, 'role' => $roleName, 'badgeCode' => $badgeCode, @@ -242,7 +238,7 @@ class ScannerController extends BaseApiController }) ->first(); - if (! $user || ! $this->isStaffUser((int) $user->id)) { + if (!$user || !$this->isStaffUser((int) $user->id)) { return null; } @@ -259,7 +255,7 @@ class ScannerController extends BaseApiController foreach ($roles as $role) { $name = trim((string) ($role->role_name ?? '')); - if ($name !== '' && ! in_array($name, ['parent', 'guest', 'student'], true)) { + if ($name !== '' && !in_array($name, ['parent', 'guest', 'student'], true)) { return true; } } @@ -291,7 +287,7 @@ class ScannerController extends BaseApiController } $row = $builder->orderByDesc('sc.id')->first(); - if (! $row && Schema::hasColumn('student_class', 'school_year')) { + if (!$row && Schema::hasColumn('student_class', 'school_year')) { $row = DB::table('student_class as sc') ->select('sc.class_section_id', 'cs.class_id', 'cs.class_section_name') ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'sc.class_section_id') @@ -333,9 +329,8 @@ class ScannerController extends BaseApiController ->where('school_year', $schoolYear) ->first(); - if (! $record) { + if (!$record) { $this->addAttendanceRecord($classSectionId, $studentId, $schoolId, $newStatus, $semester, $schoolYear, $operatorId); - return; } @@ -388,7 +383,6 @@ class ScannerController extends BaseApiController 'updated_at' => utc_now(), ]); $record->save(); - return; } @@ -430,13 +424,13 @@ class ScannerController extends BaseApiController return [ 'id' => (int) ($student['id'] ?? 0), 'schoolId' => $student['school_id'] ?? null, - 'name' => trim((string) ($student['firstname'] ?? '').' '.(string) ($student['lastname'] ?? '')), + 'name' => trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? '')), 'firstName' => $student['firstname'] ?? null, 'lastName' => $student['lastname'] ?? null, 'grade' => $student['registration_grade'] ?? null, 'classSectionId' => isset($assignment['class_section_id']) ? (int) $assignment['class_section_id'] : null, 'classSectionName' => $assignment['class_section_name'] ?? null, - 'badgeCode' => ! empty($student['rfid_tag']) ? $student['rfid_tag'] : ($student['school_id'] ?? null), + 'badgeCode' => !empty($student['rfid_tag']) ? $student['rfid_tag'] : ($student['school_id'] ?? null), ]; } @@ -533,7 +527,7 @@ class ScannerController extends BaseApiController $outstandingBalance = 0.0; $paymentStatus = 'Unknown'; - if (! empty($payments)) { + if (!empty($payments)) { $latest = $payments[0]; $paymentStatus = (string) ($latest['status'] ?? 'Unknown'); $outstandingBalance = (float) ($latest['balance'] ?? 0); @@ -556,7 +550,7 @@ class ScannerController extends BaseApiController { $issues = []; $payments = $summary['payments'] ?? []; - if (! empty($payments)) { + if (!empty($payments)) { $latest = $payments[0]; $balance = (float) ($latest['balance'] ?? 0); $status = strtolower(trim((string) ($latest['status'] ?? ''))); @@ -565,9 +559,9 @@ class ScannerController extends BaseApiController 'category' => 'payment', 'severity' => 'critical', 'title' => 'Payment balance due', - 'detail' => '$'.number_format($balance, 2).' outstanding', + 'detail' => '$' . number_format($balance, 2) . ' outstanding', ]; - } elseif ($status !== '' && ! in_array($status, ['paid', 'full', 'full payment', 'complete', 'completed'], true)) { + } elseif ($status !== '' && !in_array($status, ['paid', 'full', 'full payment', 'complete', 'completed'], true)) { $issues[] = [ 'category' => 'payment', 'severity' => 'warning', @@ -584,7 +578,7 @@ class ScannerController extends BaseApiController 'category' => 'grades', 'severity' => (float) $semesterScore < 60 ? 'critical' : 'warning', 'title' => 'Grade concern', - 'detail' => 'Semester score '.number_format((float) $semesterScore, 1), + 'detail' => 'Semester score ' . number_format((float) $semesterScore, 1), ]; } @@ -593,7 +587,7 @@ class ScannerController extends BaseApiController $issues[] = [ 'category' => 'grades', 'severity' => 'warning', - 'title' => $label.' average below target', + 'title' => $label . ' average below target', 'detail' => number_format((float) $grading[$key], 1), ]; } @@ -605,7 +599,7 @@ class ScannerController extends BaseApiController 'category' => 'attendance', 'severity' => 'warning', 'title' => 'Repeated lateness', - 'detail' => (int) $attendance['late'].' late attendance records', + 'detail' => (int) $attendance['late'] . ' late attendance records', ]; } @@ -653,7 +647,7 @@ class ScannerController extends BaseApiController { $label = trim(str_replace('_', ' ', $flagType)); if ($label !== '') { - return ucwords($label).' flag'; + return ucwords($label) . ' flag'; } return match ($category) { @@ -685,10 +679,10 @@ class ScannerController extends BaseApiController private function createLateSlipPayload(array $student, array $assignment, array $term, \DateTimeImmutable $schoolNow, \DateTimeImmutable $lateCutoff, int $operatorId, ?string $previousStatus): array { - $studentName = trim((string) ($student['firstname'] ?? '').' '.(string) ($student['lastname'] ?? '')); + $studentName = trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? '')); $grade = (string) ($student['registration_grade'] ?? $assignment['class_section_name'] ?? ''); $cutoffLabel = $lateCutoff->format('h:i A'); - $reason = 'Arrived after '.$cutoffLabel; + $reason = 'Arrived after ' . $cutoffLabel; $adminName = $this->operatorName($operatorId); $slip = [ 'school_year' => $term['school_year'], @@ -720,7 +714,7 @@ class ScannerController extends BaseApiController $logId = (int) ($created->id ?? 0); $logged = $logId > 0; } catch (\Throwable $e) { - Log::error('Badge scan late slip log failed: '.$e->getMessage()); + Log::error('Badge scan late slip log failed: ' . $e->getMessage()); } } @@ -741,15 +735,15 @@ class ScannerController extends BaseApiController 'reason' => $reason, 'adminName' => $adminName, 'cutoffTime' => $cutoffLabel, - 'message' => 'Late slip receipt generated for arrival after '.$cutoffLabel.'.', + 'message' => 'Late slip receipt generated for arrival after ' . $cutoffLabel . '.', 'text' => implode("\n", [ 'Al Rahma School at ISGL', - 'School Year: '.$slip['school_year'], - 'Student Name: '.$studentName, - 'Date: '.$displayDate.' Time In: '.$displayTime, - 'Grade: '.$grade, - 'Reason: '.$reason, - 'Admin: '.$adminName, + 'School Year: ' . $slip['school_year'], + 'Student Name: ' . $studentName, + 'Date: ' . $displayDate . ' Time In: ' . $displayTime, + 'Grade: ' . $grade, + 'Reason: ' . $reason, + 'Admin: ' . $adminName, ]), ]; } @@ -766,19 +760,18 @@ class ScannerController extends BaseApiController $date = $schoolNow->format('Y-m-d'); foreach (['H:i:s', 'H:i', 'g:i A', 'h:i A', 'g:i a', 'h:i a'] as $format) { - $parsed = \DateTimeImmutable::createFromFormat('!'.$format, $configured, $timezone); + $parsed = \DateTimeImmutable::createFromFormat('!' . $format, $configured, $timezone); if ($parsed instanceof \DateTimeImmutable) { return $schoolNow->setTime((int) $parsed->format('H'), (int) $parsed->format('i'), (int) $parsed->format('s')); } } - $timestamp = strtotime($date.' '.$configured); + $timestamp = strtotime($date . ' ' . $configured); if ($timestamp !== false) { - return (new \DateTimeImmutable('@'.$timestamp))->setTimezone($timezone); + return (new \DateTimeImmutable('@' . $timestamp))->setTimezone($timezone); } - Log::warning(self::LATE_CUTOFF_CONFIG_KEY.' has invalid value "'.$configured.'"; using '.self::DEFAULT_LATE_CUTOFF); - + Log::warning(self::LATE_CUTOFF_CONFIG_KEY . ' has invalid value "' . $configured . '"; using ' . self::DEFAULT_LATE_CUTOFF); return $schoolNow->setTime(10, 0, 0); } @@ -787,7 +780,6 @@ class ScannerController extends BaseApiController $timezone = new \DateTimeZone('America/New_York'); try { $utc = new \DateTimeZone('UTC'); - return (new \DateTimeImmutable($scannedAt, $utc))->setTimezone($timezone); } catch (\Throwable) { return new \DateTimeImmutable('now', $timezone); @@ -800,7 +792,7 @@ class ScannerController extends BaseApiController try { $user = User::query()->select('firstname', 'lastname', 'email')->find($operatorId); if ($user) { - $name = trim((string) ($user->firstname ?? '').' '.(string) ($user->lastname ?? '')); + $name = trim((string) ($user->firstname ?? '') . ' ' . (string) ($user->lastname ?? '')); if ($name !== '') { return $name; } @@ -808,7 +800,7 @@ class ScannerController extends BaseApiController return (string) ($user->email ?? ''); } } catch (\Throwable $e) { - Log::error('Badge scan operator lookup failed: '.$e->getMessage()); + Log::error('Badge scan operator lookup failed: ' . $e->getMessage()); } } @@ -841,7 +833,7 @@ class ScannerController extends BaseApiController private function logScan(string $badgeCode, ?string $personType, ?int $personId, string $action, string $status, int $operatorId, string $stationId, string $message, string $scannedAt): void { try { - if (! Schema::hasTable('badge_scan_logs')) { + if (!Schema::hasTable('badge_scan_logs')) { return; } @@ -858,7 +850,7 @@ class ScannerController extends BaseApiController 'created_at' => utc_now(), ]); } catch (\Throwable $e) { - Log::error('Badge scan log failed: '.$e->getMessage()); + Log::error('Badge scan log failed: ' . $e->getMessage()); } } diff --git a/app/Http/Controllers/Api/Scores/FinalController.php b/app/Http/Controllers/Api/Scores/FinalController.php index 14812192..4b9b705c 100644 --- a/app/Http/Controllers/Api/Scores/FinalController.php +++ b/app/Http/Controllers/Api/Scores/FinalController.php @@ -135,6 +135,9 @@ class FinalController extends BaseApiController } } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Scores/HomeworkController.php b/app/Http/Controllers/Api/Scores/HomeworkController.php index 8c44ab69..f38e491c 100644 --- a/app/Http/Controllers/Api/Scores/HomeworkController.php +++ b/app/Http/Controllers/Api/Scores/HomeworkController.php @@ -158,6 +158,9 @@ class HomeworkController extends BaseApiController } } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Scores/MidtermController.php b/app/Http/Controllers/Api/Scores/MidtermController.php index a88d13b7..8ddcb304 100644 --- a/app/Http/Controllers/Api/Scores/MidtermController.php +++ b/app/Http/Controllers/Api/Scores/MidtermController.php @@ -135,6 +135,9 @@ class MidtermController extends BaseApiController } } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Scores/ParticipationController.php b/app/Http/Controllers/Api/Scores/ParticipationController.php index fa5ed8d2..98b18796 100644 --- a/app/Http/Controllers/Api/Scores/ParticipationController.php +++ b/app/Http/Controllers/Api/Scores/ParticipationController.php @@ -138,6 +138,9 @@ class ParticipationController extends BaseApiController } } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Scores/ProjectController.php b/app/Http/Controllers/Api/Scores/ProjectController.php index 85566cdc..9954763f 100644 --- a/app/Http/Controllers/Api/Scores/ProjectController.php +++ b/app/Http/Controllers/Api/Scores/ProjectController.php @@ -159,6 +159,9 @@ class ProjectController extends BaseApiController } } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Scores/QuizController.php b/app/Http/Controllers/Api/Scores/QuizController.php index 4b979b65..2a17f95d 100644 --- a/app/Http/Controllers/Api/Scores/QuizController.php +++ b/app/Http/Controllers/Api/Scores/QuizController.php @@ -158,6 +158,9 @@ class QuizController extends BaseApiController } } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Scores/ScoreCommentController.php b/app/Http/Controllers/Api/Scores/ScoreCommentController.php index ad2e3a82..24a1c873 100644 --- a/app/Http/Controllers/Api/Scores/ScoreCommentController.php +++ b/app/Http/Controllers/Api/Scores/ScoreCommentController.php @@ -88,7 +88,7 @@ class ScoreCommentController extends BaseApiController $userId ); - if (! empty($result['errors'])) { + if (!empty($result['errors'])) { return response()->json(['ok' => false, 'errors' => $result['errors']], 422); } @@ -112,13 +112,16 @@ class ScoreCommentController extends BaseApiController $userId ); - if (! empty($result['errors'])) { + if (!empty($result['errors'])) { return response()->json(['ok' => false, 'errors' => $result['errors']], 422); } return response()->json(['ok' => true]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Scores/ScoreController.php b/app/Http/Controllers/Api/Scores/ScoreController.php index 825bd21c..c8b465a2 100644 --- a/app/Http/Controllers/Api/Scores/ScoreController.php +++ b/app/Http/Controllers/Api/Scores/ScoreController.php @@ -81,6 +81,9 @@ class ScoreController extends BaseApiController return response()->json(['ok' => true] + $data); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (request()->user()?->id ?? auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Settings/ConfigurationAdminController.php b/app/Http/Controllers/Api/Settings/ConfigurationAdminController.php index 62b1ef1b..b95add77 100644 --- a/app/Http/Controllers/Api/Settings/ConfigurationAdminController.php +++ b/app/Http/Controllers/Api/Settings/ConfigurationAdminController.php @@ -39,7 +39,7 @@ class ConfigurationAdminController extends BaseApiController public function update(ConfigurationUpdateRequest $request, int $id): JsonResponse { $config = $this->service->update($id, $request->validated()); - if (! $config) { + if (!$config) { return response()->json(['ok' => false, 'message' => 'Configuration not found.'], 404); } @@ -52,7 +52,7 @@ class ConfigurationAdminController extends BaseApiController public function destroy(int $id): JsonResponse { $deleted = $this->service->delete($id); - if (! $deleted) { + if (!$deleted) { return response()->json(['ok' => false, 'message' => 'Configuration not found.'], 404); } @@ -62,7 +62,7 @@ class ConfigurationAdminController extends BaseApiController public function getByKey(string $configKey): JsonResponse { $config = $this->service->getByKey($configKey); - if (! $config) { + if (!$config) { return response()->json(['ok' => false, 'message' => 'Configuration not found.'], 404); } diff --git a/app/Http/Controllers/Api/Settings/EventController.php b/app/Http/Controllers/Api/Settings/EventController.php index 6bbb4f35..f245ccf8 100644 --- a/app/Http/Controllers/Api/Settings/EventController.php +++ b/app/Http/Controllers/Api/Settings/EventController.php @@ -50,7 +50,7 @@ class EventController extends BaseApiController public function show(int $eventId): JsonResponse { $event = $this->listService->find($eventId); - if (! $event) { + if (!$event) { return response()->json(['ok' => false, 'message' => 'Event not found.'], 404); } @@ -73,7 +73,6 @@ class EventController extends BaseApiController $result = $this->managementService->create($payload, $request->file('flyer'), $guard); } catch (\Throwable $e) { Log::error('Event creation failed.', ['error' => $e->getMessage()]); - return response()->json(['ok' => false, 'message' => 'Failed to create event.'], 500); } @@ -177,6 +176,9 @@ class EventController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Settings/PreferencesController.php b/app/Http/Controllers/Api/Settings/PreferencesController.php index 633414bb..2a93b8c2 100644 --- a/app/Http/Controllers/Api/Settings/PreferencesController.php +++ b/app/Http/Controllers/Api/Settings/PreferencesController.php @@ -58,7 +58,7 @@ class PreferencesController extends BaseApiController public function showForUser(int $userId): JsonResponse { $row = Preferences::query()->where('user_id', $userId)->first(); - if (! $row) { + if (!$row) { return $this->error('Preferences not found.', Response::HTTP_NOT_FOUND); } @@ -82,8 +82,7 @@ class PreferencesController extends BaseApiController try { $saved = $this->commandService->upsert($guard, $request->validated()); } catch (\Throwable $e) { - Log::error('Preferences save failed: '.$e->getMessage()); - + Log::error('Preferences save failed: ' . $e->getMessage()); return $this->error('Unable to save preferences.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -104,8 +103,7 @@ class PreferencesController extends BaseApiController try { $saved = $this->commandService->upsert($userId, $request->validated()); } catch (\Throwable $e) { - Log::error('Preferences update failed: '.$e->getMessage()); - + Log::error('Preferences update failed: ' . $e->getMessage()); return $this->error('Unable to save preferences.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -119,7 +117,7 @@ class PreferencesController extends BaseApiController public function destroy(int $userId): JsonResponse { $row = Preferences::query()->where('user_id', $userId)->first(); - if (! $row) { + if (!$row) { return $this->error('Preferences not found.', Response::HTTP_NOT_FOUND); } @@ -128,18 +126,20 @@ class PreferencesController extends BaseApiController try { $deleted = $this->commandService->delete($row); } catch (\Throwable $e) { - Log::error('Preferences delete failed: '.$e->getMessage()); - + Log::error('Preferences delete failed: ' . $e->getMessage()); return $this->error('Unable to delete preferences.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! $deleted) { + if (!$deleted) { return $this->error('Unable to delete preferences.', Response::HTTP_INTERNAL_SERVER_ERROR); } return $this->success(null, 'Preferences deleted.'); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Settings/SchoolCalendarController.php b/app/Http/Controllers/Api/Settings/SchoolCalendarController.php index 53eccb0a..d6cf29e8 100644 --- a/app/Http/Controllers/Api/Settings/SchoolCalendarController.php +++ b/app/Http/Controllers/Api/Settings/SchoolCalendarController.php @@ -99,7 +99,7 @@ class SchoolCalendarController extends BaseApiController public function show(int $eventId): JsonResponse { $event = $this->queryService->findEvent($eventId); - if (! $event) { + if (!$event) { return $this->error('Event not found.', Response::HTTP_NOT_FOUND); } @@ -116,8 +116,7 @@ class SchoolCalendarController extends BaseApiController try { $result = $this->mutationService->create($payload, $targets); } catch (\Throwable $e) { - Log::error('SchoolCalendar store failed: '.$e->getMessage()); - + Log::error('SchoolCalendar store failed: ' . $e->getMessage()); return $this->error('Failed to save event.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -130,7 +129,7 @@ class SchoolCalendarController extends BaseApiController public function update(SchoolCalendarUpdateRequest $request, int $eventId): JsonResponse { $event = $this->queryService->findEvent($eventId); - if (! $event) { + if (!$event) { return $this->error('Event not found.', Response::HTTP_NOT_FOUND); } @@ -140,8 +139,7 @@ class SchoolCalendarController extends BaseApiController try { $result = $this->mutationService->update($event, $payload, $targets); } catch (\Throwable $e) { - Log::error('SchoolCalendar update failed: '.$e->getMessage()); - + Log::error('SchoolCalendar update failed: ' . $e->getMessage()); return $this->error('Failed to update event.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -154,15 +152,14 @@ class SchoolCalendarController extends BaseApiController public function destroy(int $eventId): JsonResponse { $event = $this->queryService->findEvent($eventId); - if (! $event) { + if (!$event) { return $this->error('Event not found.', Response::HTTP_NOT_FOUND); } try { $this->mutationService->delete($event); } catch (\Throwable $e) { - Log::error('SchoolCalendar delete failed: '.$e->getMessage()); - + Log::error('SchoolCalendar delete failed: ' . $e->getMessage()); return $this->error('Failed to delete event.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -172,12 +169,15 @@ class SchoolCalendarController extends BaseApiController private function extractEmailTargets(array $payload): array { return [ - 'parents' => ! empty($payload['send_email_parent']), - 'teachers' => ! empty($payload['send_email_teacher']), - 'admins' => ! empty($payload['send_email_admin']), + 'parents' => !empty($payload['send_email_parent']), + 'teachers' => !empty($payload['send_email_teacher']), + 'admins' => !empty($payload['send_email_admin']), ]; } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Settings/SettingsController.php b/app/Http/Controllers/Api/Settings/SettingsController.php index 396b9ae9..2c37f826 100644 --- a/app/Http/Controllers/Api/Settings/SettingsController.php +++ b/app/Http/Controllers/Api/Settings/SettingsController.php @@ -40,8 +40,7 @@ class SettingsController extends BaseApiController try { $updated = $this->settingsService->update($request->validated(), $guard); } catch (\Throwable $e) { - Log::error('Settings update failed: '.$e->getMessage()); - + Log::error('Settings update failed: ' . $e->getMessage()); return $this->error('Unable to update settings.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -50,6 +49,9 @@ class SettingsController extends BaseApiController ], 'Settings updated.'); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Staff/StaffController.php b/app/Http/Controllers/Api/Staff/StaffController.php index 38e53478..38418b0e 100644 --- a/app/Http/Controllers/Api/Staff/StaffController.php +++ b/app/Http/Controllers/Api/Staff/StaffController.php @@ -9,7 +9,6 @@ use App\Http\Requests\Staff\StaffUpdateRequest; use App\Http\Resources\Staff\StaffCollection; use App\Http\Resources\Staff\StaffResource; use App\Models\Staff; -use App\Models\User; use App\Services\Staff\StaffCommandService; use App\Services\Staff\StaffQueryService; use Illuminate\Http\JsonResponse; @@ -48,12 +47,12 @@ class StaffController extends BaseApiController public function show(int $id): JsonResponse { $staff = $this->queryService->find($id); - if (! $staff) { + if (!$staff) { return $this->error('Staff member not found.', Response::HTTP_NOT_FOUND); } $this->authorize('view', $staff); - $staff->school_id = User::getSchoolIdByUserId((int) ($staff->user_id ?? 0)); + $staff->school_id = \App\Models\User::getSchoolIdByUserId((int) ($staff->user_id ?? 0)); return $this->success([ 'staff' => new StaffResource($staff), @@ -67,8 +66,7 @@ class StaffController extends BaseApiController try { $staff = $this->commandService->create($request->validated()); } catch (\Throwable $e) { - Log::error('Staff create failed: '.$e->getMessage()); - + Log::error('Staff create failed: ' . $e->getMessage()); return $this->error($e->getMessage(), Response::HTTP_BAD_REQUEST); } @@ -80,7 +78,7 @@ class StaffController extends BaseApiController public function update(StaffUpdateRequest $request, int $id): JsonResponse { $staff = $this->queryService->find($id); - if (! $staff) { + if (!$staff) { return $this->error('Staff member not found.', Response::HTTP_NOT_FOUND); } @@ -89,8 +87,7 @@ class StaffController extends BaseApiController try { $updated = $this->commandService->update($staff, $request->validated()); } catch (\Throwable $e) { - Log::error('Staff update failed: '.$e->getMessage()); - + Log::error('Staff update failed: ' . $e->getMessage()); return $this->error('Unable to update staff.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -102,7 +99,7 @@ class StaffController extends BaseApiController public function destroy(int $id): JsonResponse { $staff = $this->queryService->find($id); - if (! $staff) { + if (!$staff) { return $this->error('Staff member not found.', Response::HTTP_NOT_FOUND); } @@ -111,12 +108,11 @@ class StaffController extends BaseApiController try { $deleted = $this->commandService->delete($staff); } catch (\Throwable $e) { - Log::error('Staff delete failed: '.$e->getMessage()); - + Log::error('Staff delete failed: ' . $e->getMessage()); return $this->error('Unable to delete staff.', Response::HTTP_INTERNAL_SERVER_ERROR); } - if (! $deleted) { + if (!$deleted) { return $this->error('Unable to delete staff.', Response::HTTP_INTERNAL_SERVER_ERROR); } diff --git a/app/Http/Controllers/Api/Staff/TeacherController.php b/app/Http/Controllers/Api/Staff/TeacherController.php index fa761c7f..83c2ea10 100644 --- a/app/Http/Controllers/Api/Staff/TeacherController.php +++ b/app/Http/Controllers/Api/Staff/TeacherController.php @@ -124,12 +124,12 @@ class TeacherController extends BaseApiController private function teacherPayload(?array $teacher, int $userId): ?array { - if (! $teacher) { + if (!$teacher) { $model = User::query()->find($userId); $teacher = $model?->toArray(); } - if (! $teacher) { + if (!$teacher) { return null; } @@ -142,6 +142,9 @@ class TeacherController extends BaseApiController ]; } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/StatsController.php b/app/Http/Controllers/Api/StatsController.php index e4aa3575..412aa165 100644 --- a/app/Http/Controllers/Api/StatsController.php +++ b/app/Http/Controllers/Api/StatsController.php @@ -2,8 +2,10 @@ namespace App\Http\Controllers\Api; +use App\Http\Controllers\Api\BaseApiController; use App\Models\Stats; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Schema; use Symfony\Component\HttpFoundation\Response; class StatsController extends BaseApiController @@ -11,12 +13,14 @@ class StatsController extends BaseApiController public function index() { try { - $stats = Stats::query()->get()->toArray(); + if (! Schema::hasTable('stats')) { + return $this->success([], 'Statistics retrieved successfully'); + } + $stats = Stats::query()->get()->toArray(); return $this->success($stats, 'Statistics retrieved successfully'); } catch (\Throwable $e) { Log::error('Stats retrieval error: '.$e->getMessage()); - return $this->respondError('Failed to retrieve statistics', Response::HTTP_INTERNAL_SERVER_ERROR); } } diff --git a/app/Http/Controllers/Api/Students/StudentController.php b/app/Http/Controllers/Api/Students/StudentController.php index 3800bb6b..0454f4eb 100644 --- a/app/Http/Controllers/Api/Students/StudentController.php +++ b/app/Http/Controllers/Api/Students/StudentController.php @@ -15,6 +15,7 @@ use App\Http\Resources\Students\StudentClassSectionResource; use App\Http\Resources\Students\StudentRemovedResource; use App\Http\Resources\Students\StudentScoreCardRowResource; use App\Models\AttendanceRecord; +use App\Models\ClassSection; use App\Models\EmergencyContact; use App\Models\Incident; use App\Models\SemesterScore; @@ -67,7 +68,7 @@ class StudentController extends BaseApiController $data = array_merge($request->query->all(), $request->all(), $request->json()->all()); $validator = Validator::make($data, [ 'school_year' => ['nullable', 'string', 'max:50'], - 'parent_id' => ['nullable', 'integer', 'min:1'], + 'parent_id' => ['required', 'integer', 'min:1'], 'parent_ids' => ['nullable', 'array'], 'parent_ids.*' => ['integer', 'min:1'], ]); @@ -81,10 +82,10 @@ class StudentController extends BaseApiController $payload = $validator->validated(); $parentIds = []; - if (! empty($payload['parent_ids'])) { + if (!empty($payload['parent_ids'])) { $parentIds = array_values(array_unique(array_map('intval', $payload['parent_ids']))); } - if (! empty($payload['parent_id'])) { + if (!empty($payload['parent_id'])) { $parentIds[] = (int) $payload['parent_id']; } $parentIds = array_values(array_unique(array_filter($parentIds))); @@ -148,7 +149,7 @@ class StudentController extends BaseApiController public function show(int $studentId): JsonResponse { $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return response()->json(['ok' => false, 'message' => 'Student not found.'], 404); } @@ -192,17 +193,17 @@ class StudentController extends BaseApiController 'firstname' => ['required', 'string', 'max:150'], 'lastname' => ['required', 'string', 'max:150'], 'dob' => ['nullable', 'date'], - 'age' => ['nullable', 'integer', 'min:0'], - 'gender' => ['nullable', 'string', 'max:20'], + 'age' => ['required', 'integer', 'min:0'], + 'gender' => ['required', 'string', 'max:20'], 'is_active' => ['nullable', 'boolean'], 'registration_grade' => ['nullable', 'string', 'max:50'], 'is_new' => ['nullable', 'boolean'], - 'photo_consent' => ['nullable', 'boolean'], - 'parent_id' => ['nullable', 'integer', 'min:1'], + 'photo_consent' => ['required', 'boolean'], + 'parent_id' => ['required', 'integer', 'min:1'], 'registration_date' => ['nullable', 'date'], 'tuition_paid' => ['nullable', 'boolean'], 'semester' => ['nullable', 'string', 'max:50'], - 'year_of_registration' => ['nullable', 'integer', 'min:1900'], + 'year_of_registration' => ['required', 'integer', 'min:1900'], 'school_year' => ['required', 'string', 'max:50'], 'medical_conditions' => ['nullable', 'string'], 'allergies' => ['nullable', 'string'], @@ -229,7 +230,26 @@ class StudentController extends BaseApiController } $payload = $validator->validated(); - $student = Student::query()->create($payload); + $studentPayload = collect($payload)->only([ + 'school_id', + 'firstname', + 'lastname', + 'dob', + 'age', + 'gender', + 'is_active', + 'registration_grade', + 'is_new', + 'photo_consent', + 'parent_id', + 'registration_date', + 'tuition_paid', + 'semester', + 'year_of_registration', + 'school_year', + ])->all(); + + $student = Student::query()->create($studentPayload); if (empty($student->school_id)) { $student->school_id = $this->generateSchoolId($student->id); @@ -243,7 +263,7 @@ class StudentController extends BaseApiController if (array_key_exists('allergies', $payload)) { $healthPayload['allergies'] = $payload['allergies']; } - if (! empty($healthPayload)) { + if (!empty($healthPayload)) { $this->profileService->updateStudent($student->id, $healthPayload); } @@ -360,7 +380,7 @@ class StudentController extends BaseApiController public function destroy(int $studentId): JsonResponse { $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return response()->json(['ok' => false, 'message' => 'Student not found.'], 404); } @@ -502,8 +522,8 @@ class StudentController extends BaseApiController $rows = AttendanceRecord::query() ->where('student_id', $studentId) - ->when(! empty($payload['school_year']), fn ($q) => $q->where('school_year', $payload['school_year'])) - ->when(! empty($payload['semester']), fn ($q) => $q->where('semester', $payload['semester'])) + ->when(!empty($payload['school_year']), fn ($q) => $q->where('school_year', $payload['school_year'])) + ->when(!empty($payload['semester']), fn ($q) => $q->where('semester', $payload['semester'])) ->orderBy('school_year', 'desc') ->orderBy('semester', 'desc') ->get() @@ -534,8 +554,8 @@ class StudentController extends BaseApiController $rows = Incident::query() ->where('student_id', $studentId) - ->when(! empty($payload['school_year']), fn ($q) => $q->where('school_year', $payload['school_year'])) - ->when(! empty($payload['semester']), fn ($q) => $q->where('semester', $payload['semester'])) + ->when(!empty($payload['school_year']), fn ($q) => $q->where('school_year', $payload['school_year'])) + ->when(!empty($payload['semester']), fn ($q) => $q->where('semester', $payload['semester'])) ->orderByDesc('incident_datetime') ->get() ->toArray(); @@ -565,8 +585,8 @@ class StudentController extends BaseApiController $rows = SemesterScore::query() ->where('student_id', $studentId) - ->when(! empty($payload['school_year']), fn ($q) => $q->where('school_year', $payload['school_year'])) - ->when(! empty($payload['semester']), fn ($q) => $q->where('semester', $payload['semester'])) + ->when(!empty($payload['school_year']), fn ($q) => $q->where('school_year', $payload['school_year'])) + ->when(!empty($payload['semester']), fn ($q) => $q->where('semester', $payload['semester'])) ->orderBy('school_year', 'desc') ->orderBy('semester', 'desc') ->get() @@ -591,12 +611,12 @@ class StudentController extends BaseApiController public function parents(int $studentId): JsonResponse { $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return response()->json(['ok' => false, 'message' => 'Student not found.'], 404); } $parent = null; - if (! empty($student->parent_id)) { + if (!empty($student->parent_id)) { $parent = User::query() ->select(['id', 'firstname', 'lastname', 'email', 'cellphone']) ->find((int) $student->parent_id); @@ -612,7 +632,7 @@ class StudentController extends BaseApiController public function emergencyContacts(int $studentId): JsonResponse { $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return response()->json(['ok' => false, 'message' => 'Student not found.'], 404); } @@ -620,7 +640,7 @@ class StudentController extends BaseApiController if (Schema::hasColumn('emergency_contacts', 'student_id')) { $query->where('student_id', $studentId); } - if (! empty($student->parent_id)) { + if (!empty($student->parent_id)) { $query->orWhere('parent_id', $student->parent_id); } @@ -639,7 +659,7 @@ class StudentController extends BaseApiController public function addEmergencyContact(Request $request, int $studentId): JsonResponse { $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return response()->json(['ok' => false, 'message' => 'Student not found.'], 404); } @@ -682,7 +702,7 @@ class StudentController extends BaseApiController public function updateEmergencyContact(Request $request, int $studentId, int $contactId): JsonResponse { $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return response()->json(['ok' => false, 'message' => 'Student not found.'], 404); } @@ -704,7 +724,7 @@ class StudentController extends BaseApiController } $contact = EmergencyContact::query()->find($contactId); - if (! $contact) { + if (!$contact) { return response()->json(['ok' => false, 'message' => 'Contact not found.'], 404); } @@ -735,7 +755,7 @@ class StudentController extends BaseApiController } $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return response()->json(['ok' => false, 'message' => 'Student not found.'], 404); } @@ -758,14 +778,14 @@ class StudentController extends BaseApiController } $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return response()->json(['ok' => false, 'message' => 'Student not found.'], 404); } $file = $request->file('photo'); $ext = $file->getClientOriginalExtension() ?: 'jpg'; - $path = "student-photos/{$studentId}.".strtolower($ext); - Storage::disk('public')->putFileAs('student-photos', $file, "{$studentId}.".strtolower($ext)); + $path = "student-photos/{$studentId}." . strtolower($ext); + Storage::disk('public')->putFileAs('student-photos', $file, "{$studentId}." . strtolower($ext)); return response()->json([ 'ok' => true, @@ -780,7 +800,7 @@ class StudentController extends BaseApiController $disk = Storage::disk('public'); foreach ($candidates as $ext) { - $path = $base.'.'.$ext; + $path = $base . '.' . $ext; if ($disk->exists($path)) { return response()->json([ 'ok' => true, @@ -795,14 +815,13 @@ class StudentController extends BaseApiController private function generateSchoolId(int $studentId): string { $year = (int) date('y'); - - return 'STU'.$year.str_pad((string) $studentId, 4, '0', STR_PAD_LEFT); + return 'STU' . $year . str_pad((string) $studentId, 4, '0', STR_PAD_LEFT); } public function scoreCard(int $studentId): JsonResponse { $result = $this->scoreCardService->scoreCard($studentId); - if (! $result['ok']) { + if (!$result['ok']) { return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Not found.'], 404); } diff --git a/app/Http/Controllers/Api/Subjects/SubjectCurriculumController.php b/app/Http/Controllers/Api/Subjects/SubjectCurriculumController.php index 9602d637..d9681de7 100644 --- a/app/Http/Controllers/Api/Subjects/SubjectCurriculumController.php +++ b/app/Http/Controllers/Api/Subjects/SubjectCurriculumController.php @@ -35,7 +35,7 @@ class SubjectCurriculumController extends BaseApiController public function show(int $id): JsonResponse { $entry = SubjectCurriculum::query()->find($id); - if (! $entry) { + if (!$entry) { return response()->json(['ok' => false, 'message' => 'Curriculum entry not found.'], 404); } @@ -58,7 +58,7 @@ class SubjectCurriculumController extends BaseApiController public function update(SubjectCurriculumUpdateRequest $request, int $id): JsonResponse { $entry = $this->service->update($id, $request->validated()); - if (! $entry) { + if (!$entry) { return response()->json(['ok' => false, 'message' => 'Curriculum entry not found.'], 404); } @@ -71,7 +71,7 @@ class SubjectCurriculumController extends BaseApiController public function destroy(int $id): JsonResponse { $deleted = $this->service->delete($id); - if (! $deleted) { + if (!$deleted) { return response()->json(['ok' => false, 'message' => 'Curriculum entry not found.'], 404); } diff --git a/app/Http/Controllers/Api/Support/SupportController.php b/app/Http/Controllers/Api/Support/SupportController.php index 075a8fe2..beb0522d 100644 --- a/app/Http/Controllers/Api/Support/SupportController.php +++ b/app/Http/Controllers/Api/Support/SupportController.php @@ -64,13 +64,12 @@ class SupportController extends BaseApiController $payload = $request->validated(); $payload['user_email'] = $user->email ?? null; - $payload['user_name'] = trim(($user->firstname ?? '').' '.($user->lastname ?? '')); + $payload['user_name'] = trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? '')); try { $result = $this->supportService->create((int) $user->id, $payload); } catch (\Throwable $e) { - Log::error('Support request failed: '.$e->getMessage()); - + Log::error('Support request failed: ' . $e->getMessage()); return $this->error('Unable to submit support request.', Response::HTTP_INTERNAL_SERVER_ERROR); } @@ -87,6 +86,9 @@ class SupportController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/System/DashboardController.php b/app/Http/Controllers/Api/System/DashboardController.php index 5e4f9544..0acb1e99 100644 --- a/app/Http/Controllers/Api/System/DashboardController.php +++ b/app/Http/Controllers/Api/System/DashboardController.php @@ -18,7 +18,7 @@ class DashboardController extends BaseApiController public function route(): JsonResponse { $user = auth()->user(); - if (! $user) { + if (!$user) { return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED); } diff --git a/app/Http/Controllers/Api/System/DashboardRedirectController.php b/app/Http/Controllers/Api/System/DashboardRedirectController.php index a4c1a75d..d4de52d8 100644 --- a/app/Http/Controllers/Api/System/DashboardRedirectController.php +++ b/app/Http/Controllers/Api/System/DashboardRedirectController.php @@ -15,12 +15,13 @@ class DashboardRedirectController extends Controller public function __construct( private DashboardRouteService $service, private ApplicationUrlService $urls, - ) {} + ) { + } public function dashboard(): RedirectResponse { $user = auth()->user(); - if (! $user) { + if (!$user) { return redirect()->guest($this->urls->webLoginUrl()); } diff --git a/app/Http/Controllers/Api/System/DatabaseHealthController.php b/app/Http/Controllers/Api/System/DatabaseHealthController.php index 70b9bfbd..92f9995f 100644 --- a/app/Http/Controllers/Api/System/DatabaseHealthController.php +++ b/app/Http/Controllers/Api/System/DatabaseHealthController.php @@ -17,7 +17,7 @@ class DatabaseHealthController extends BaseApiController public function index(): JsonResponse { $result = $this->healthService->check(); - if (! $result['ok']) { + if (!$result['ok']) { return $this->error('Database connection failed.', Response::HTTP_SERVICE_UNAVAILABLE, [ 'error' => $result['error'], ]); diff --git a/app/Http/Controllers/Api/System/NavBuilderController.php b/app/Http/Controllers/Api/System/NavBuilderController.php index 944bcfbf..eecb1ca7 100644 --- a/app/Http/Controllers/Api/System/NavBuilderController.php +++ b/app/Http/Controllers/Api/System/NavBuilderController.php @@ -8,8 +8,8 @@ use App\Http\Requests\System\NavItemStoreRequest; use App\Http\Resources\System\NavBuilderDataResource; use App\Http\Resources\System\NavItemResource; use App\Models\NavItem; -use App\Services\Navigation\NavbarService; use App\Services\Navigation\NavBuilderService; +use App\Services\Navigation\NavbarService; use Illuminate\Http\JsonResponse; use Illuminate\Support\Facades\Log; use Symfony\Component\HttpFoundation\Response; @@ -67,7 +67,7 @@ class NavBuilderController extends BaseApiController $deleted = $this->builderService->delete($id); - if (! $deleted) { + if (!$deleted) { return $this->error('Menu item not found.', Response::HTTP_NOT_FOUND); } @@ -81,8 +81,7 @@ class NavBuilderController extends BaseApiController try { $this->builderService->reorder($request->validated()['orders']); } catch (\Throwable $e) { - Log::error('Nav reorder failed: '.$e->getMessage()); - + Log::error('Nav reorder failed: ' . $e->getMessage()); return $this->error('Unable to reorder items.', Response::HTTP_INTERNAL_SERVER_ERROR); } diff --git a/app/Http/Controllers/Api/System/StatsController.php b/app/Http/Controllers/Api/System/StatsController.php index 1a884382..9c0c648b 100644 --- a/app/Http/Controllers/Api/System/StatsController.php +++ b/app/Http/Controllers/Api/System/StatsController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers\Api\System; use App\Http\Controllers\Api\Core\BaseApiController; use App\Models\Stats; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Schema; use Symfony\Component\HttpFoundation\Response; class StatsController extends BaseApiController @@ -12,12 +13,14 @@ class StatsController extends BaseApiController public function index() { try { - $stats = Stats::query()->get()->toArray(); + if (! Schema::hasTable('stats')) { + return $this->success([], 'Statistics retrieved successfully'); + } + $stats = Stats::query()->get()->toArray(); return $this->success($stats, 'Statistics retrieved successfully'); } catch (\Throwable $e) { Log::error('Stats retrieval error: '.$e->getMessage()); - return $this->respondError('Failed to retrieve statistics', Response::HTTP_INTERNAL_SERVER_ERROR); } } diff --git a/app/Http/Controllers/Api/Ui/UiController.php b/app/Http/Controllers/Api/Ui/UiController.php index e0c5e405..9a3f177c 100644 --- a/app/Http/Controllers/Api/Ui/UiController.php +++ b/app/Http/Controllers/Api/Ui/UiController.php @@ -30,6 +30,9 @@ class UiController extends BaseApiController ], 'Style updated.'); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Api/Users/UserController.php b/app/Http/Controllers/Api/Users/UserController.php index f12d4d32..f477641a 100644 --- a/app/Http/Controllers/Api/Users/UserController.php +++ b/app/Http/Controllers/Api/Users/UserController.php @@ -151,6 +151,9 @@ class UserController extends BaseApiController ]); } + /** + * @return int|JsonResponse + */ private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); diff --git a/app/Http/Controllers/Web/SchoolYearAdminPageController.php b/app/Http/Controllers/Web/SchoolYearAdminPageController.php index 7aac1b71..84c0714a 100644 --- a/app/Http/Controllers/Web/SchoolYearAdminPageController.php +++ b/app/Http/Controllers/Web/SchoolYearAdminPageController.php @@ -17,7 +17,8 @@ class SchoolYearAdminPageController extends Controller public function __construct( private SchoolYearClosureService $service, private SchoolYearResolver $resolver - ) {} + ) { + } public function show(Request $request): View { diff --git a/app/Http/Controllers/Web/TeacherCalendarPageController.php b/app/Http/Controllers/Web/TeacherCalendarPageController.php index e1555272..d9a9b807 100644 --- a/app/Http/Controllers/Web/TeacherCalendarPageController.php +++ b/app/Http/Controllers/Web/TeacherCalendarPageController.php @@ -16,7 +16,8 @@ class TeacherCalendarPageController extends Controller private SchoolCalendarQueryService $queryService, private SchoolCalendarMeetingService $meetingService, private SchoolCalendarFormatterService $formatterService, - ) {} + ) { + } public function show(): View { diff --git a/app/Http/Middleware/ApiDocsAuth.php b/app/Http/Middleware/ApiDocsAuth.php index 14ee1c02..21e7fae4 100644 --- a/app/Http/Middleware/ApiDocsAuth.php +++ b/app/Http/Middleware/ApiDocsAuth.php @@ -15,7 +15,7 @@ class ApiDocsAuth public function handle(Request $request, Closure $next): Response { $user = Auth::user(); - if (! $user) { + if (!$user) { $authHeader = (string) $request->header('Authorization'); if ($authHeader !== '' && stripos($authHeader, 'Bearer ') === 0) { $token = trim(substr($authHeader, 7)); @@ -34,11 +34,11 @@ class ApiDocsAuth } } - if (! $user) { + if (!$user) { return $this->deny('Unauthorized access to documentation.', 401); } - if (! $this->userIsAdmin((int) $user->id)) { + if (!$this->userIsAdmin((int) $user->id)) { return $this->deny('Admin privileges required.', 403); } diff --git a/app/Http/Middleware/ApiJwtAuth.php b/app/Http/Middleware/ApiJwtAuth.php index afcfaa48..f6f2d6c1 100644 --- a/app/Http/Middleware/ApiJwtAuth.php +++ b/app/Http/Middleware/ApiJwtAuth.php @@ -15,7 +15,7 @@ class ApiJwtAuth { try { $user = JWTAuth::parseToken()->authenticate(); - if (! $user) { + if (!$user) { return response()->json(['status' => false, 'message' => 'Unauthorized.'], 401); } diff --git a/app/Http/Middleware/CleanupScheduler.php b/app/Http/Middleware/CleanupScheduler.php index f383011a..f2fe3ac1 100644 --- a/app/Http/Middleware/CleanupScheduler.php +++ b/app/Http/Middleware/CleanupScheduler.php @@ -9,7 +9,9 @@ use Symfony\Component\HttpFoundation\Response; class CleanupScheduler { - public function __construct(private CleanupSchedulerService $service) {} + public function __construct(private CleanupSchedulerService $service) + { + } public function handle(Request $request, Closure $next): Response { diff --git a/app/Http/Middleware/EnsurePrintRequestsAdminAccess.php b/app/Http/Middleware/EnsurePrintRequestsAdminAccess.php index 467089e5..32055dc3 100644 --- a/app/Http/Middleware/EnsurePrintRequestsAdminAccess.php +++ b/app/Http/Middleware/EnsurePrintRequestsAdminAccess.php @@ -28,7 +28,8 @@ class EnsurePrintRequestsAdminAccess ->toArray(); foreach ( - ['administrator', 'admin', 'principal', 'vice_principal', 'vice-principal'] as $allowed + ['administrator', 'admin', 'principal', 'vice_principal', 'vice-principal'] + as $allowed ) { if (in_array($allowed, $roles, true)) { return $next($request); diff --git a/app/Http/Middleware/EnsureSchoolYearEditable.php b/app/Http/Middleware/EnsureSchoolYearEditable.php index dc96c1a9..7bbfc881 100644 --- a/app/Http/Middleware/EnsureSchoolYearEditable.php +++ b/app/Http/Middleware/EnsureSchoolYearEditable.php @@ -12,11 +12,13 @@ use Symfony\Component\HttpFoundation\Response; class EnsureSchoolYearEditable { - public function __construct(private SchoolYearWriteGuard $guard) {} + public function __construct(private SchoolYearWriteGuard $guard) + { + } public function handle(Request $request, Closure $next): Response { - if (! in_array(strtoupper($request->method()), ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { + if (!in_array(strtoupper($request->method()), ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { return $next($request); } @@ -82,7 +84,7 @@ class EnsureSchoolYearEditable private function lookupYear(string $id, string $table, string $column): ?string { - if (! ctype_digit($id) || ! DB::getSchemaBuilder()->hasTable($table)) { + if (!ctype_digit($id) || !DB::getSchemaBuilder()->hasTable($table)) { return null; } diff --git a/app/Http/Middleware/MultiAuth.php b/app/Http/Middleware/MultiAuth.php index bc1cd473..ee12e081 100644 --- a/app/Http/Middleware/MultiAuth.php +++ b/app/Http/Middleware/MultiAuth.php @@ -16,7 +16,6 @@ class MultiAuth $sanctumUser = Auth::guard('sanctum')->user(); if ($sanctumUser) { Auth::setUser($sanctumUser); - return $next($request); } @@ -26,7 +25,6 @@ class MultiAuth $jwtUser = JWTAuth::setToken($token)->authenticate(); if ($jwtUser) { Auth::setUser($jwtUser); - return $next($request); } } catch (JWTException $e) { diff --git a/app/Http/Middleware/PrimeTimezone.php b/app/Http/Middleware/PrimeTimezone.php index ab71d84c..34811419 100644 --- a/app/Http/Middleware/PrimeTimezone.php +++ b/app/Http/Middleware/PrimeTimezone.php @@ -9,7 +9,9 @@ use Symfony\Component\HttpFoundation\Response; class PrimeTimezone { - public function __construct(private TimeService $timeService) {} + public function __construct(private TimeService $timeService) + { + } public function handle(Request $request, Closure $next): Response { diff --git a/app/Http/Middleware/RequirePermission.php b/app/Http/Middleware/RequirePermission.php index b78d9f0a..bd5ae72b 100644 --- a/app/Http/Middleware/RequirePermission.php +++ b/app/Http/Middleware/RequirePermission.php @@ -9,7 +9,9 @@ use Symfony\Component\HttpFoundation\Response; class RequirePermission { - public function __construct(private PermissionCheckService $permissions) {} + public function __construct(private PermissionCheckService $permissions) + { + } public function handle(Request $request, Closure $next, string $permission): Response { @@ -18,11 +20,10 @@ class RequirePermission return response()->json(['status' => false, 'message' => 'Unauthorized.'], 401); } - if (! $this->permissions->hasPermission($userId, $permission)) { + if (!$this->permissions->hasPermission($userId, $permission)) { if ($request->expectsJson()) { return response()->json(['status' => false, 'message' => 'Access denied.'], 403); } - return response()->json(['status' => false, 'message' => 'Access denied.'], 403); } diff --git a/app/Http/Requests/Admin/SaveCompetitionScoresRequest.php b/app/Http/Requests/Admin/SaveCompetitionScoresRequest.php index 74d8e7de..c9b71b46 100644 --- a/app/Http/Requests/Admin/SaveCompetitionScoresRequest.php +++ b/app/Http/Requests/Admin/SaveCompetitionScoresRequest.php @@ -2,11 +2,10 @@ namespace App\Http\Requests\Admin; -use App\Controllers\Admin\CompetitionWinnersController; use Illuminate\Foundation\Http\FormRequest; /** - * Mirrors legacy {@see CompetitionWinnersController::saveScores()} accepted fields. + * Mirrors legacy {@see \App\Controllers\Admin\CompetitionWinnersController::saveScores()} accepted fields. */ class SaveCompetitionScoresRequest extends FormRequest { diff --git a/app/Http/Requests/Admin/UpdateCompetitionWinnerRequest.php b/app/Http/Requests/Admin/UpdateCompetitionWinnerRequest.php index 11da37fc..5610abd3 100644 --- a/app/Http/Requests/Admin/UpdateCompetitionWinnerRequest.php +++ b/app/Http/Requests/Admin/UpdateCompetitionWinnerRequest.php @@ -3,4 +3,6 @@ namespace App\Http\Requests\Admin; /** Validation for updating competition settings (legacy `CompetitionWinnersController::update`). */ -class UpdateCompetitionWinnerRequest extends StoreCompetitionWinnerRequest {} +class UpdateCompetitionWinnerRequest extends StoreCompetitionWinnerRequest +{ +} diff --git a/app/Http/Requests/Administrator/SubmitAdministratorAbsenceRequest.php b/app/Http/Requests/Administrator/SubmitAdministratorAbsenceRequest.php index 78efdab5..fc2ace6f 100644 --- a/app/Http/Requests/Administrator/SubmitAdministratorAbsenceRequest.php +++ b/app/Http/Requests/Administrator/SubmitAdministratorAbsenceRequest.php @@ -31,4 +31,4 @@ class SubmitAdministratorAbsenceRequest extends ApiFormRequest 'reason.required' => 'Reason is required.', ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Api/Admin/IndexAdminProgressRequest.php b/app/Http/Requests/Api/Admin/IndexAdminProgressRequest.php index 2a54a14a..0ef66ddf 100644 --- a/app/Http/Requests/Api/Admin/IndexAdminProgressRequest.php +++ b/app/Http/Requests/Api/Admin/IndexAdminProgressRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests\Api\Admin; +use App\Http\Requests\ApiFormRequest; use Illuminate\Validation\Rule; class IndexAdminProgressRequest extends FormRequest @@ -35,4 +36,4 @@ class IndexAdminProgressRequest extends FormRequest 'status' => $this->filled('status') ? (string) $this->query('status') : '', ]); } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Api/Admin/SaveAdminNotificationSubjectsRequest.php b/app/Http/Requests/Api/Admin/SaveAdminNotificationSubjectsRequest.php index f9ea9b87..7b00fa43 100644 --- a/app/Http/Requests/Api/Admin/SaveAdminNotificationSubjectsRequest.php +++ b/app/Http/Requests/Api/Admin/SaveAdminNotificationSubjectsRequest.php @@ -2,6 +2,8 @@ namespace App\Http\Requests\Admin; +use App\Http\Requests\ApiFormRequest; + class SaveAdminNotificationSubjectsRequest extends FormRequest { public function authorize(): bool @@ -16,4 +18,4 @@ class SaveAdminNotificationSubjectsRequest extends FormRequest // dynamic structure: subjects[adminId][subjectKey]=true OR array of subject strings ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Api/Admin/SavePrintNotificationRecipientsRequest.php b/app/Http/Requests/Api/Admin/SavePrintNotificationRecipientsRequest.php index f37a6ee8..b5c72993 100644 --- a/app/Http/Requests/Api/Admin/SavePrintNotificationRecipientsRequest.php +++ b/app/Http/Requests/Api/Admin/SavePrintNotificationRecipientsRequest.php @@ -2,6 +2,8 @@ namespace App\Http\Requests\Admin; +use App\Http\Requests\ApiFormRequest; + class SavePrintNotificationRecipientsRequest extends FormRequest { public function authorize(): bool @@ -15,4 +17,4 @@ class SavePrintNotificationRecipientsRequest extends FormRequest 'notify' => ['required', 'array'], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Api/Admin/SendTeacherSubmissionNotificationsRequest.php b/app/Http/Requests/Api/Admin/SendTeacherSubmissionNotificationsRequest.php index 5e58cc8a..5819b909 100644 --- a/app/Http/Requests/Api/Admin/SendTeacherSubmissionNotificationsRequest.php +++ b/app/Http/Requests/Api/Admin/SendTeacherSubmissionNotificationsRequest.php @@ -2,6 +2,8 @@ namespace App\Http\Requests\Admin; +use App\Http\Requests\ApiFormRequest; + class SendTeacherSubmissionNotificationsRequest extends FormRequest { public function authorize(): bool @@ -17,4 +19,4 @@ class SendTeacherSubmissionNotificationsRequest extends FormRequest 'missing_items' => ['nullable', 'array'], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Assignment/StoreStudentAssignmentRequest.php b/app/Http/Requests/Assignment/StoreStudentAssignmentRequest.php index 8c7485a0..2e9069e5 100644 --- a/app/Http/Requests/Assignment/StoreStudentAssignmentRequest.php +++ b/app/Http/Requests/Assignment/StoreStudentAssignmentRequest.php @@ -2,6 +2,8 @@ namespace App\Http\Requests; +use App\Http\Requests\ApiFormRequest; + class StoreStudentAssignmentRequest extends FormRequest { public function authorize(): bool @@ -12,11 +14,11 @@ class StoreStudentAssignmentRequest extends FormRequest public function rules(): array { return [ - 'student_id' => ['required', 'integer', 'exists:students,id'], + 'student_id' => ['required', 'integer', 'exists:students,id'], 'class_section_id' => ['required', 'integer', 'exists:class_sections,id'], - 'semester' => ['nullable', 'string', 'max:50'], - 'school_year' => ['nullable', 'string', 'max:50'], - 'description' => ['nullable', 'string'], + 'semester' => ['nullable', 'string', 'max:50'], + 'school_year' => ['nullable', 'string', 'max:50'], + 'description' => ['nullable', 'string'], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Attendance/AdminAddAttendanceEntryRequest.php b/app/Http/Requests/Attendance/AdminAddAttendanceEntryRequest.php index bdf7828d..fe24e995 100644 --- a/app/Http/Requests/Attendance/AdminAddAttendanceEntryRequest.php +++ b/app/Http/Requests/Attendance/AdminAddAttendanceEntryRequest.php @@ -24,4 +24,4 @@ class AdminAddAttendanceEntryRequest extends FormRequest 'is_reported' => ['nullable', 'in:yes,no'], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Attendance/SaveAdminAttendanceRequest.php b/app/Http/Requests/Attendance/SaveAdminAttendanceRequest.php index b6cbc816..630d5e2f 100644 --- a/app/Http/Requests/Attendance/SaveAdminAttendanceRequest.php +++ b/app/Http/Requests/Attendance/SaveAdminAttendanceRequest.php @@ -21,4 +21,4 @@ class SaveAdminAttendanceRequest extends FormRequest 'staff' => ['nullable', 'array'], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Attendance/SaveStaffAttendanceCellRequest.php b/app/Http/Requests/Attendance/SaveStaffAttendanceCellRequest.php index 40c79fdb..bea0e6ef 100644 --- a/app/Http/Requests/Attendance/SaveStaffAttendanceCellRequest.php +++ b/app/Http/Requests/Attendance/SaveStaffAttendanceCellRequest.php @@ -23,4 +23,4 @@ class SaveStaffAttendanceCellRequest extends FormRequest 'reason' => ['nullable', 'string'], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Attendance/TeacherSubmitAttendanceRequest.php b/app/Http/Requests/Attendance/TeacherSubmitAttendanceRequest.php index dd32766d..fafef9bb 100644 --- a/app/Http/Requests/Attendance/TeacherSubmitAttendanceRequest.php +++ b/app/Http/Requests/Attendance/TeacherSubmitAttendanceRequest.php @@ -26,4 +26,4 @@ class TeacherSubmitAttendanceRequest extends FormRequest 'teachers' => ['required', 'array', 'min:1'], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Attendance/UpdateAttendanceManagementRequest.php b/app/Http/Requests/Attendance/UpdateAttendanceManagementRequest.php index 325c34af..eded3b8c 100644 --- a/app/Http/Requests/Attendance/UpdateAttendanceManagementRequest.php +++ b/app/Http/Requests/Attendance/UpdateAttendanceManagementRequest.php @@ -26,4 +26,4 @@ class UpdateAttendanceManagementRequest extends FormRequest 'is_reported' => ['nullable'], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/AttendanceTracking/ComposeAttendanceEmailRequest.php b/app/Http/Requests/AttendanceTracking/ComposeAttendanceEmailRequest.php index 6d8c2614..ad954676 100644 --- a/app/Http/Requests/AttendanceTracking/ComposeAttendanceEmailRequest.php +++ b/app/Http/Requests/AttendanceTracking/ComposeAttendanceEmailRequest.php @@ -14,9 +14,9 @@ class ComposeAttendanceEmailRequest extends ApiFormRequest public function rules(): array { return [ - 'student_id' => ['required', 'integer', 'min:1'], - 'code' => ['nullable', 'string'], - 'variant' => ['nullable', 'string'], + 'student_id' => ['required', 'integer', 'min:1'], + 'code' => ['nullable', 'string'], + 'variant' => ['nullable', 'string'], 'incident_date' => ['nullable', 'date_format:Y-m-d'], ]; } diff --git a/app/Http/Requests/AttendanceTracking/RecordAttendanceTrackingRequest.php b/app/Http/Requests/AttendanceTracking/RecordAttendanceTrackingRequest.php index 9e71011d..9c00dec7 100644 --- a/app/Http/Requests/AttendanceTracking/RecordAttendanceTrackingRequest.php +++ b/app/Http/Requests/AttendanceTracking/RecordAttendanceTrackingRequest.php @@ -14,13 +14,13 @@ class RecordAttendanceTrackingRequest extends ApiFormRequest public function rules(): array { return [ - 'student_id' => ['required', 'integer', 'min:1'], - 'date' => ['required', 'date_format:Y-m-d'], + 'student_id' => ['required', 'integer', 'min:1'], + 'date' => ['required', 'date_format:Y-m-d'], 'parent_email' => ['nullable', 'email'], - 'parent_name' => ['nullable', 'string'], + 'parent_name' => ['nullable', 'string'], 'subject_type' => ['nullable', 'string'], - 'semester' => ['nullable', 'string'], - 'school_year' => ['nullable', 'string'], + 'semester' => ['nullable', 'string'], + 'school_year' => ['nullable', 'string'], ]; } } diff --git a/app/Http/Requests/AttendanceTracking/SaveAttendanceNotificationNoteRequest.php b/app/Http/Requests/AttendanceTracking/SaveAttendanceNotificationNoteRequest.php index 9276272a..1d57f480 100644 --- a/app/Http/Requests/AttendanceTracking/SaveAttendanceNotificationNoteRequest.php +++ b/app/Http/Requests/AttendanceTracking/SaveAttendanceNotificationNoteRequest.php @@ -14,13 +14,13 @@ class SaveAttendanceNotificationNoteRequest extends ApiFormRequest public function rules(): array { return [ - 'student_id' => ['required', 'integer', 'min:1'], - 'code' => ['required', 'string'], - 'note' => ['required', 'string'], + 'student_id' => ['required', 'integer', 'min:1'], + 'code' => ['required', 'string'], + 'note' => ['required', 'string'], 'incident_date' => ['nullable', 'date_format:Y-m-d'], - 'to' => ['nullable', 'email'], - 'subject' => ['nullable', 'string'], - 'variant' => ['nullable', 'string'], + 'to' => ['nullable', 'email'], + 'subject' => ['nullable', 'string'], + 'variant' => ['nullable', 'string'], ]; } } diff --git a/app/Http/Requests/AttendanceTracking/SendAttendanceManualEmailRequest.php b/app/Http/Requests/AttendanceTracking/SendAttendanceManualEmailRequest.php index bca44af7..0994b8d9 100644 --- a/app/Http/Requests/AttendanceTracking/SendAttendanceManualEmailRequest.php +++ b/app/Http/Requests/AttendanceTracking/SendAttendanceManualEmailRequest.php @@ -14,12 +14,12 @@ class SendAttendanceManualEmailRequest extends ApiFormRequest public function rules(): array { return [ - 'student_id' => ['required', 'integer', 'min:1'], - 'to' => ['required', 'email'], - 'subject' => ['required', 'string'], - 'body_html' => ['required', 'string'], - 'code' => ['required', 'string'], - 'variant' => ['nullable', 'string'], + 'student_id' => ['required', 'integer', 'min:1'], + 'to' => ['required', 'email'], + 'subject' => ['required', 'string'], + 'body_html' => ['required', 'string'], + 'code' => ['required', 'string'], + 'variant' => ['nullable', 'string'], 'incident_date' => ['nullable', 'date_format:Y-m-d'], ]; } diff --git a/app/Http/Requests/Auth/RegisterRequest.php b/app/Http/Requests/Auth/RegisterRequest.php index ff57feda..13401f00 100644 --- a/app/Http/Requests/Auth/RegisterRequest.php +++ b/app/Http/Requests/Auth/RegisterRequest.php @@ -8,7 +8,7 @@ class RegisterRequest extends ApiFormRequest { public static function ruleset(): array { - return (new self)->rules(); + return (new self())->rules(); } public function authorize(): bool diff --git a/app/Http/Requests/Badges/BadgePrintStatusRequest.php b/app/Http/Requests/Badges/BadgePrintStatusRequest.php index 86429035..4cf174a0 100644 --- a/app/Http/Requests/Badges/BadgePrintStatusRequest.php +++ b/app/Http/Requests/Badges/BadgePrintStatusRequest.php @@ -17,7 +17,7 @@ class BadgePrintStatusRequest extends FormRequest if (is_string($userIds)) { $userIds = array_filter(array_map('trim', explode(',', $userIds)), 'strlen'); - } elseif (! is_array($userIds)) { + } elseif (!is_array($userIds)) { $userIds = $userIds ? [$userIds] : []; } @@ -40,4 +40,4 @@ class BadgePrintStatusRequest extends FormRequest { return $this->input('user_ids', []); } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Badges/GenerateBadgePdfRequest.php b/app/Http/Requests/Badges/GenerateBadgePdfRequest.php index c1bc01a8..20f7684b 100644 --- a/app/Http/Requests/Badges/GenerateBadgePdfRequest.php +++ b/app/Http/Requests/Badges/GenerateBadgePdfRequest.php @@ -17,7 +17,7 @@ class GenerateBadgePdfRequest extends FormRequest if (is_string($userIds)) { $userIds = array_filter(array_map('trim', explode(',', $userIds)), 'strlen'); - } elseif (! is_array($userIds)) { + } elseif (!is_array($userIds)) { $userIds = $userIds ? [$userIds] : []; } @@ -38,4 +38,4 @@ class GenerateBadgePdfRequest extends FormRequest 'classes' => ['nullable', 'array'], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Badges/LogBadgePrintRequest.php b/app/Http/Requests/Badges/LogBadgePrintRequest.php index b2fabafd..2e5362c3 100644 --- a/app/Http/Requests/Badges/LogBadgePrintRequest.php +++ b/app/Http/Requests/Badges/LogBadgePrintRequest.php @@ -17,7 +17,7 @@ class LogBadgePrintRequest extends FormRequest if (is_string($userIds)) { $userIds = array_filter(array_map('trim', explode(',', $userIds)), 'strlen'); - } elseif (! is_array($userIds)) { + } elseif (!is_array($userIds)) { $userIds = $userIds ? [$userIds] : []; } @@ -38,4 +38,4 @@ class LogBadgePrintRequest extends FormRequest 'classes' => ['nullable', 'array'], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/ClassProgress/ClassProgressIndexRequest.php b/app/Http/Requests/ClassProgress/ClassProgressIndexRequest.php index fd6ac3e0..aded861c 100644 --- a/app/Http/Requests/ClassProgress/ClassProgressIndexRequest.php +++ b/app/Http/Requests/ClassProgress/ClassProgressIndexRequest.php @@ -2,6 +2,8 @@ namespace App\Http\Requests\ClassProgress; +use App\Http\Requests\ClassProgress\ClassProgressFormRequest; + class ClassProgressIndexRequest extends ClassProgressFormRequest { public function authorize(): bool @@ -21,7 +23,7 @@ class ClassProgressIndexRequest extends ClassProgressFormRequest 'week_start' => ['nullable', 'date_format:Y-m-d'], 'week_end' => ['nullable', 'date_format:Y-m-d'], 'subject' => ['nullable', 'string', 'max:120'], - 'status' => $statuses ? ['nullable', 'in:'.implode(',', $statuses)] : ['nullable', 'string'], + 'status' => $statuses ? ['nullable', 'in:' . implode(',', $statuses)] : ['nullable', 'string'], 'group_by_week' => ['nullable', 'boolean'], 'page' => ['nullable', 'integer', 'min:1'], 'per_page' => ['nullable', 'integer', 'min:1', 'max:200'], diff --git a/app/Http/Requests/ClassProgress/ClassProgressMetaRequest.php b/app/Http/Requests/ClassProgress/ClassProgressMetaRequest.php index ba56c177..cb7f61ad 100644 --- a/app/Http/Requests/ClassProgress/ClassProgressMetaRequest.php +++ b/app/Http/Requests/ClassProgress/ClassProgressMetaRequest.php @@ -2,6 +2,8 @@ namespace App\Http\Requests\ClassProgress; +use App\Http\Requests\ClassProgress\ClassProgressFormRequest; + class ClassProgressMetaRequest extends ClassProgressFormRequest { public function authorize(): bool diff --git a/app/Http/Requests/ClassProgress/ClassProgressStoreRequest.php b/app/Http/Requests/ClassProgress/ClassProgressStoreRequest.php index 81dbbdb1..ea3d0e69 100644 --- a/app/Http/Requests/ClassProgress/ClassProgressStoreRequest.php +++ b/app/Http/Requests/ClassProgress/ClassProgressStoreRequest.php @@ -2,6 +2,8 @@ namespace App\Http\Requests\ClassProgress; +use App\Http\Requests\ClassProgress\ClassProgressFormRequest; + class ClassProgressStoreRequest extends ClassProgressFormRequest { public function authorize(): bool @@ -25,7 +27,7 @@ class ClassProgressStoreRequest extends ClassProgressFormRequest $sections = (array) config('progress.subject_sections', []); $maxFileKb = (int) config('progress.attachments.max_kb', 5120); $mimes = (array) config('progress.attachments.mimes', ['pdf', 'jpg', 'jpeg', 'png']); - $mimeRule = 'mimes:'.implode(',', $mimes); + $mimeRule = 'mimes:' . implode(',', $mimes); foreach ($sections as $slug => $section) { $rules["covered_{$slug}"] = ['nullable', 'string']; @@ -35,7 +37,7 @@ class ClassProgressStoreRequest extends ClassProgressFormRequest $rules["chapter_{$slug}"] = ['nullable', 'array']; $rules["chapter_{$slug}.*"] = ['nullable', 'string', 'max:120']; $rules["attachment_{$slug}"] = ['nullable', 'array']; - $rules["attachment_{$slug}.*"] = ['nullable', 'file', $mimeRule, 'max:'.$maxFileKb]; + $rules["attachment_{$slug}.*"] = ['nullable', 'file', $mimeRule, 'max:' . $maxFileKb]; } return $rules; diff --git a/app/Http/Requests/ClassProgress/ClassProgressUpdateRequest.php b/app/Http/Requests/ClassProgress/ClassProgressUpdateRequest.php index c72f8030..1919b7e5 100644 --- a/app/Http/Requests/ClassProgress/ClassProgressUpdateRequest.php +++ b/app/Http/Requests/ClassProgress/ClassProgressUpdateRequest.php @@ -2,6 +2,8 @@ namespace App\Http\Requests\ClassProgress; +use App\Http\Requests\ClassProgress\ClassProgressFormRequest; + class ClassProgressUpdateRequest extends ClassProgressFormRequest { public function authorize(): bool @@ -14,7 +16,7 @@ class ClassProgressUpdateRequest extends ClassProgressFormRequest $statuses = array_keys((array) config('progress.status_options', [])); $maxFileKb = (int) config('progress.attachments.max_kb', 5120); $mimes = (array) config('progress.attachments.mimes', ['pdf', 'jpg', 'jpeg', 'png']); - $mimeRule = 'mimes:'.implode(',', $mimes); + $mimeRule = 'mimes:' . implode(',', $mimes); return [ 'week_start' => ['nullable', 'date_format:Y-m-d'], @@ -22,11 +24,11 @@ class ClassProgressUpdateRequest extends ClassProgressFormRequest 'covered' => ['nullable', 'string'], 'homework' => ['nullable', 'string'], 'unit_title' => ['nullable', 'string', 'max:120'], - 'status' => $statuses ? ['nullable', 'in:'.implode(',', $statuses)] : ['nullable', 'string'], + 'status' => $statuses ? ['nullable', 'in:' . implode(',', $statuses)] : ['nullable', 'string'], 'support_needed' => ['nullable', 'string'], 'flags' => ['nullable', 'array'], 'attachments' => ['nullable', 'array'], - 'attachments.*' => ['nullable', 'file', $mimeRule, 'max:'.$maxFileKb], + 'attachments.*' => ['nullable', 'file', $mimeRule, 'max:' . $maxFileKb], ]; } diff --git a/app/Http/Requests/Families/FamilyComposeEmailRequest.php b/app/Http/Requests/Families/FamilyComposeEmailRequest.php index caf48ad7..3058a88c 100644 --- a/app/Http/Requests/Families/FamilyComposeEmailRequest.php +++ b/app/Http/Requests/Families/FamilyComposeEmailRequest.php @@ -10,7 +10,7 @@ class FamilyComposeEmailRequest extends ApiFormRequest { parent::prepareForValidation(); - if (! $this->has('html_message') && $this->has('html')) { + if (!$this->has('html_message') && $this->has('html')) { $this->merge(['html_message' => $this->input('html')]); } } diff --git a/app/Http/Requests/Finance/CarryforwardAdjustmentRequest.php b/app/Http/Requests/Finance/CarryforwardAdjustmentRequest.php index 7e3054bb..251e49e9 100644 --- a/app/Http/Requests/Finance/CarryforwardAdjustmentRequest.php +++ b/app/Http/Requests/Finance/CarryforwardAdjustmentRequest.php @@ -6,16 +6,12 @@ use Illuminate\Foundation\Http\FormRequest; class CarryforwardAdjustmentRequest extends FormRequest { - public function authorize(): bool - { - return true; - } - + public function authorize(): bool { return true; } public function rules(): array { return [ - 'amount' => ['required', 'numeric', 'min:0'], - 'reason' => ['nullable', 'string', 'max:255'], + 'amount' => ['required','numeric','min:0'], + 'reason' => ['nullable','string','max:255'], ]; } } diff --git a/app/Http/Requests/Finance/CarryforwardFinalizeRequest.php b/app/Http/Requests/Finance/CarryforwardFinalizeRequest.php index bdd72381..2cd75e8f 100644 --- a/app/Http/Requests/Finance/CarryforwardFinalizeRequest.php +++ b/app/Http/Requests/Finance/CarryforwardFinalizeRequest.php @@ -6,18 +6,14 @@ use Illuminate\Foundation\Http\FormRequest; class CarryforwardFinalizeRequest extends FormRequest { - public function authorize(): bool - { - return true; - } - + public function authorize(): bool { return true; } public function rules(): array { return [ - 'from_school_year' => ['required_without:id', 'string', 'max:20'], - 'to_school_year' => ['required_without:id', 'string', 'max:20'], - 'parent_id' => ['nullable', 'integer'], - 'reason' => ['nullable', 'string', 'max:255'], + 'from_school_year' => ['required_without:id','string','max:20'], + 'to_school_year' => ['required_without:id','string','max:20'], + 'parent_id' => ['nullable','integer'], + 'reason' => ['nullable','string','max:255'], ]; } } diff --git a/app/Http/Requests/Finance/CarryforwardPreviewRequest.php b/app/Http/Requests/Finance/CarryforwardPreviewRequest.php index 813fc380..7d660220 100644 --- a/app/Http/Requests/Finance/CarryforwardPreviewRequest.php +++ b/app/Http/Requests/Finance/CarryforwardPreviewRequest.php @@ -6,18 +6,14 @@ use Illuminate\Foundation\Http\FormRequest; class CarryforwardPreviewRequest extends FormRequest { - public function authorize(): bool - { - return true; - } - + public function authorize(): bool { return true; } public function rules(): array { return [ - 'from_school_year' => ['required', 'string', 'max:20'], - 'to_school_year' => ['required', 'string', 'max:20'], - 'parent_id' => ['nullable', 'integer'], - 'minimum_balance' => ['nullable', 'numeric', 'min:0'], + 'from_school_year' => ['required','string','max:20'], + 'to_school_year' => ['required','string','max:20'], + 'parent_id' => ['nullable','integer'], + 'minimum_balance' => ['nullable','numeric','min:0'], ]; } } diff --git a/app/Http/Requests/Finance/EventChargeLifecycleRequest.php b/app/Http/Requests/Finance/EventChargeLifecycleRequest.php index d689a18a..e2a4371c 100644 --- a/app/Http/Requests/Finance/EventChargeLifecycleRequest.php +++ b/app/Http/Requests/Finance/EventChargeLifecycleRequest.php @@ -6,24 +6,20 @@ use Illuminate\Foundation\Http\FormRequest; class EventChargeLifecycleRequest extends FormRequest { - public function authorize(): bool - { - return true; - } - + public function authorize(): bool { return true; } public function rules(): array { return [ - 'event_id' => ['nullable', 'integer'], - 'parent_id' => ['nullable', 'integer'], - 'student_id' => ['nullable', 'integer'], - 'school_year' => ['nullable', 'string', 'max:20'], - 'semester' => ['nullable', 'string', 'max:40'], - 'event_name' => ['nullable', 'string', 'max:255'], - 'title' => ['nullable', 'string', 'max:255'], - 'description' => ['nullable', 'string'], - 'amount' => ['nullable', 'numeric', 'min:0'], - 'invoice_id' => ['nullable', 'integer'], + 'event_id' => ['nullable','integer'], + 'parent_id' => ['nullable','integer'], + 'student_id' => ['nullable','integer'], + 'school_year' => ['nullable','string','max:20'], + 'semester' => ['nullable','string','max:40'], + 'event_name' => ['nullable','string','max:255'], + 'title' => ['nullable','string','max:255'], + 'description' => ['nullable','string'], + 'amount' => ['nullable','numeric','min:0'], + 'invoice_id' => ['nullable','integer'], ]; } } diff --git a/app/Http/Requests/Finance/FinanceNotificationLogRequest.php b/app/Http/Requests/Finance/FinanceNotificationLogRequest.php index 970299b4..e5e38aff 100644 --- a/app/Http/Requests/Finance/FinanceNotificationLogRequest.php +++ b/app/Http/Requests/Finance/FinanceNotificationLogRequest.php @@ -6,19 +6,15 @@ use Illuminate\Foundation\Http\FormRequest; class FinanceNotificationLogRequest extends FormRequest { - public function authorize(): bool - { - return true; - } - + public function authorize(): bool { return true; } public function rules(): array { return [ - 'status' => ['nullable', 'string', 'max:40'], - 'notification_type' => ['nullable', 'string', 'max:80'], - 'parent_id' => ['nullable', 'integer'], - 'date_from' => ['nullable', 'date'], - 'date_to' => ['nullable', 'date'], + 'status' => ['nullable','string','max:40'], + 'notification_type' => ['nullable','string','max:80'], + 'parent_id' => ['nullable','integer'], + 'date_from' => ['nullable','date'], + 'date_to' => ['nullable','date'], ]; } } diff --git a/app/Http/Requests/Finance/FinancialSummaryRequest.php b/app/Http/Requests/Finance/FinancialSummaryRequest.php index 36548dfb..1f1c43dd 100644 --- a/app/Http/Requests/Finance/FinancialSummaryRequest.php +++ b/app/Http/Requests/Finance/FinancialSummaryRequest.php @@ -2,4 +2,6 @@ namespace App\Http\Requests\Finance; -class FinancialSummaryRequest extends FinancialReportRequest {} +class FinancialSummaryRequest extends FinancialReportRequest +{ +} diff --git a/app/Http/Requests/Finance/FollowUpNoteRequest.php b/app/Http/Requests/Finance/FollowUpNoteRequest.php index e4979a54..23f0caa6 100644 --- a/app/Http/Requests/Finance/FollowUpNoteRequest.php +++ b/app/Http/Requests/Finance/FollowUpNoteRequest.php @@ -6,23 +6,19 @@ use Illuminate\Foundation\Http\FormRequest; class FollowUpNoteRequest extends FormRequest { - public function authorize(): bool - { - return true; - } - + public function authorize(): bool { return true; } public function rules(): array { return [ - 'invoice_id' => ['nullable', 'integer'], - 'school_year' => ['nullable', 'string', 'max:20'], - 'status' => ['nullable', 'string', 'max:60'], - 'contact_method' => ['nullable', 'string', 'max:60'], - 'promise_to_pay_date' => ['nullable', 'date'], - 'promise_to_pay_amount' => ['nullable', 'numeric', 'min:0'], - 'next_follow_up_date' => ['nullable', 'date'], - 'escalation_level' => ['nullable', 'integer', 'min:0', 'max:10'], - 'note' => ['nullable', 'string', 'max:10000'], + 'invoice_id' => ['nullable','integer'], + 'school_year' => ['nullable','string','max:20'], + 'status' => ['nullable','string','max:60'], + 'contact_method' => ['nullable','string','max:60'], + 'promise_to_pay_date' => ['nullable','date'], + 'promise_to_pay_amount' => ['nullable','numeric','min:0'], + 'next_follow_up_date' => ['nullable','date'], + 'escalation_level' => ['nullable','integer','min:0','max:10'], + 'note' => ['nullable','string','max:10000'], ]; } } diff --git a/app/Http/Requests/Finance/InstallmentPlanRequest.php b/app/Http/Requests/Finance/InstallmentPlanRequest.php index 57ff6913..e53b74d9 100644 --- a/app/Http/Requests/Finance/InstallmentPlanRequest.php +++ b/app/Http/Requests/Finance/InstallmentPlanRequest.php @@ -6,19 +6,15 @@ use Illuminate\Foundation\Http\FormRequest; class InstallmentPlanRequest extends FormRequest { - public function authorize(): bool - { - return true; - } - + public function authorize(): bool { return true; } public function rules(): array { return [ - 'plan_name' => ['nullable', 'string', 'max:120'], - 'total_amount' => ['nullable', 'numeric', 'min:0'], - 'number_of_installments' => ['required', 'integer', 'min:1', 'max:24'], - 'first_due_date' => ['required', 'date'], - 'interval_months' => ['nullable', 'integer', 'min:1', 'max:12'], + 'plan_name' => ['nullable','string','max:120'], + 'total_amount' => ['nullable','numeric','min:0'], + 'number_of_installments' => ['required','integer','min:1','max:24'], + 'first_due_date' => ['required','date'], + 'interval_months' => ['nullable','integer','min:1','max:12'], ]; } } diff --git a/app/Http/Requests/Finance/ParentPaymentFollowUpRequest.php b/app/Http/Requests/Finance/ParentPaymentFollowUpRequest.php index 24fedbe1..7309f768 100644 --- a/app/Http/Requests/Finance/ParentPaymentFollowUpRequest.php +++ b/app/Http/Requests/Finance/ParentPaymentFollowUpRequest.php @@ -6,27 +6,23 @@ use Illuminate\Foundation\Http\FormRequest; class ParentPaymentFollowUpRequest extends FormRequest { - public function authorize(): bool - { - return true; - } - + public function authorize(): bool { return true; } public function rules(): array { return [ - 'school_year' => ['nullable', 'string', 'max:20'], - 'date_from' => ['nullable', 'date'], - 'date_to' => ['nullable', 'date'], - 'minimum_balance' => ['nullable', 'numeric', 'min:0'], - 'aging_bucket' => ['nullable', 'string', 'max:40'], - 'parent_id' => ['nullable', 'integer'], - 'student_id' => ['nullable', 'integer'], - 'follow_up_status' => ['nullable', 'string', 'max:60'], - 'last_contacted_before' => ['nullable', 'date'], - 'next_follow_up_due_before' => ['nullable', 'date'], - 'promise_to_pay_due_before' => ['nullable', 'date'], - 'include_paid_invoices' => ['nullable', 'boolean'], - 'include_inactive_students' => ['nullable', 'boolean'], + 'school_year' => ['nullable','string','max:20'], + 'date_from' => ['nullable','date'], + 'date_to' => ['nullable','date'], + 'minimum_balance' => ['nullable','numeric','min:0'], + 'aging_bucket' => ['nullable','string','max:40'], + 'parent_id' => ['nullable','integer'], + 'student_id' => ['nullable','integer'], + 'follow_up_status' => ['nullable','string','max:60'], + 'last_contacted_before' => ['nullable','date'], + 'next_follow_up_due_before' => ['nullable','date'], + 'promise_to_pay_due_before' => ['nullable','date'], + 'include_paid_invoices' => ['nullable','boolean'], + 'include_inactive_students' => ['nullable','boolean'], ]; } } diff --git a/app/Http/Requests/Finance/PaymentAllocationRequest.php b/app/Http/Requests/Finance/PaymentAllocationRequest.php index a201e3f8..36f714bf 100644 --- a/app/Http/Requests/Finance/PaymentAllocationRequest.php +++ b/app/Http/Requests/Finance/PaymentAllocationRequest.php @@ -6,17 +6,13 @@ use Illuminate\Foundation\Http\FormRequest; class PaymentAllocationRequest extends FormRequest { - public function authorize(): bool - { - return true; - } - + public function authorize(): bool { return true; } public function rules(): array { return [ - 'installments' => ['nullable', 'array'], - 'installments.*.installment_id' => ['required_with:installments', 'integer'], - 'installments.*.amount' => ['required_with:installments', 'numeric', 'min:0.01'], + 'installments' => ['nullable','array'], + 'installments.*.installment_id' => ['required_with:installments','integer'], + 'installments.*.amount' => ['required_with:installments','numeric','min:0.01'], ]; } } diff --git a/app/Http/Requests/Incidents/IncidentStoreRequest.php b/app/Http/Requests/Incidents/IncidentStoreRequest.php index 0368835c..b9de4dbb 100644 --- a/app/Http/Requests/Incidents/IncidentStoreRequest.php +++ b/app/Http/Requests/Incidents/IncidentStoreRequest.php @@ -44,7 +44,7 @@ class IncidentStoreRequest extends ApiFormRequest return [ 'student_id' => ['required', 'integer', 'min:1', 'exists:students,id'], 'grade' => ['required', 'string', 'max:50'], - 'incident' => ['required', 'string', 'in:'.implode(',', $incidentTypes)], + 'incident' => ['required', 'string', 'in:' . implode(',', $incidentTypes)], 'description' => ['required', 'string', 'max:2000'], 'incident_state' => ['nullable', 'string', 'in:Open,Closed,Canceled'], 'state_description' => ['nullable', 'string', 'max:2000'], diff --git a/app/Http/Requests/Promotions/AdminListPromotionsRequest.php b/app/Http/Requests/Promotions/AdminListPromotionsRequest.php index e90290e3..f6b54c47 100644 --- a/app/Http/Requests/Promotions/AdminListPromotionsRequest.php +++ b/app/Http/Requests/Promotions/AdminListPromotionsRequest.php @@ -30,7 +30,7 @@ class AdminListPromotionsRequest extends ApiFormRequest $status = $data['status'] ?? null; if (is_string($status) && $status !== '') { $status = [$status]; - } elseif (! is_array($status)) { + } elseif (!is_array($status)) { $status = null; } diff --git a/app/Http/Requests/Promotions/ParentEnrollmentStepRequest.php b/app/Http/Requests/Promotions/ParentEnrollmentStepRequest.php index 9b4103d7..8689d033 100644 --- a/app/Http/Requests/Promotions/ParentEnrollmentStepRequest.php +++ b/app/Http/Requests/Promotions/ParentEnrollmentStepRequest.php @@ -25,7 +25,6 @@ class ParentEnrollmentStepRequest extends ApiFormRequest $steps[$field] = (bool) $data[$field]; } } - return $steps; } } diff --git a/app/Http/Requests/PurchaseOrders/PurchaseOrderStoreRequest.php b/app/Http/Requests/PurchaseOrders/PurchaseOrderStoreRequest.php index 6bc12b16..aea68722 100644 --- a/app/Http/Requests/PurchaseOrders/PurchaseOrderStoreRequest.php +++ b/app/Http/Requests/PurchaseOrders/PurchaseOrderStoreRequest.php @@ -17,7 +17,7 @@ class PurchaseOrderStoreRequest extends ApiFormRequest return [ 'po_number' => ['required', 'string', 'max:60'], 'supplier_id' => ['required', 'integer', 'min:1', 'exists:suppliers,id'], - 'status' => ['nullable', 'string', 'in:'.implode(',', PurchaseOrder::allowedStatuses())], + 'status' => ['nullable', 'string', 'in:' . implode(',', PurchaseOrder::allowedStatuses())], 'order_date' => ['nullable', 'date'], 'expected_date' => ['nullable', 'date', 'after_or_equal:order_date'], 'notes' => ['nullable', 'string', 'max:5000'], diff --git a/app/Http/Requests/Refunds/RefundDecisionRequest.php b/app/Http/Requests/Refunds/RefundDecisionRequest.php index 788a76ec..e5db2dea 100644 --- a/app/Http/Requests/Refunds/RefundDecisionRequest.php +++ b/app/Http/Requests/Refunds/RefundDecisionRequest.php @@ -15,7 +15,7 @@ class RefundDecisionRequest extends ApiFormRequest public function rules(): array { return [ - 'status' => ['required', 'string', 'in:'.implode(',', [ + 'status' => ['required', 'string', 'in:' . implode(',', [ Refund::STATUS_APPROVED, Refund::STATUS_REJECTED, ])], diff --git a/app/Http/Requests/Refunds/RefundIndexRequest.php b/app/Http/Requests/Refunds/RefundIndexRequest.php index 17ffb2cd..3f18109b 100644 --- a/app/Http/Requests/Refunds/RefundIndexRequest.php +++ b/app/Http/Requests/Refunds/RefundIndexRequest.php @@ -15,7 +15,7 @@ class RefundIndexRequest extends ApiFormRequest public function rules(): array { return [ - 'status' => ['nullable', 'string', 'in:'.implode(',', [ + 'status' => ['nullable', 'string', 'in:' . implode(',', [ Refund::STATUS_PENDING, Refund::STATUS_APPROVED, Refund::STATUS_PARTIAL, diff --git a/app/Http/Requests/Reports/Stickers/StickerFormDataRequest.php b/app/Http/Requests/Reports/Stickers/StickerFormDataRequest.php index a1b04b3f..9644faf2 100644 --- a/app/Http/Requests/Reports/Stickers/StickerFormDataRequest.php +++ b/app/Http/Requests/Reports/Stickers/StickerFormDataRequest.php @@ -10,7 +10,7 @@ class StickerFormDataRequest extends ApiFormRequest { parent::prepareForValidation(); - if (! $this->has('class_section_id') && $this->has('class_id')) { + if (!$this->has('class_section_id') && $this->has('class_id')) { $this->merge(['class_section_id' => $this->input('class_id')]); } } diff --git a/app/Http/Requests/Reports/Stickers/StickerPrintRequest.php b/app/Http/Requests/Reports/Stickers/StickerPrintRequest.php index 2522926e..651ec973 100644 --- a/app/Http/Requests/Reports/Stickers/StickerPrintRequest.php +++ b/app/Http/Requests/Reports/Stickers/StickerPrintRequest.php @@ -11,7 +11,7 @@ class StickerPrintRequest extends ApiFormRequest { parent::prepareForValidation(); - if (! $this->has('class_section_id') && $this->has('class_id')) { + if (!$this->has('class_section_id') && $this->has('class_id')) { $this->merge(['class_section_id' => $this->input('class_id')]); } } @@ -53,7 +53,7 @@ class StickerPrintRequest extends ApiFormRequest $hasClass = $this->filled('class_section_id'); $printAll = (bool) $this->input('print_all', false); - if (! $hasStudent && ! $hasClass && ! $printAll) { + if (!$hasStudent && !$hasClass && !$printAll) { $validator->errors()->add('selection', 'Please select a student or class, or set print_all.'); } }); diff --git a/app/Http/Requests/Reports/Stickers/StickerStudentsByClassRequest.php b/app/Http/Requests/Reports/Stickers/StickerStudentsByClassRequest.php index 5ae919ca..089ff9a0 100644 --- a/app/Http/Requests/Reports/Stickers/StickerStudentsByClassRequest.php +++ b/app/Http/Requests/Reports/Stickers/StickerStudentsByClassRequest.php @@ -10,7 +10,7 @@ class StickerStudentsByClassRequest extends ApiFormRequest { parent::prepareForValidation(); - if (! $this->has('class_section_id') && $this->has('class_id')) { + if (!$this->has('class_section_id') && $this->has('class_id')) { $this->merge(['class_section_id' => $this->input('class_id')]); } } diff --git a/app/Http/Requests/Roles/PermissionStoreRequest.php b/app/Http/Requests/Roles/PermissionStoreRequest.php index ee365b15..cd97a21c 100644 --- a/app/Http/Requests/Roles/PermissionStoreRequest.php +++ b/app/Http/Requests/Roles/PermissionStoreRequest.php @@ -3,6 +3,7 @@ namespace App\Http\Requests\Roles; use App\Http\Requests\ApiFormRequest; +use Illuminate\Validation\Rule; class PermissionStoreRequest extends ApiFormRequest { diff --git a/app/Http/Requests/Security/IpBanRequest.php b/app/Http/Requests/Security/IpBanRequest.php index e599414d..1c89a523 100644 --- a/app/Http/Requests/Security/IpBanRequest.php +++ b/app/Http/Requests/Security/IpBanRequest.php @@ -26,7 +26,7 @@ class IpBanRequest extends ApiFormRequest $validator->after(function (Validator $validator) { $id = $this->input('id'); $ip = $this->input('ip'); - if (! $id && ! $ip) { + if (!$id && !$ip) { $validator->errors()->add('id', 'Either id or ip is required.'); } }); diff --git a/app/Http/Requests/Security/IpUnbanRequest.php b/app/Http/Requests/Security/IpUnbanRequest.php index 31291e76..e5ad0e3a 100644 --- a/app/Http/Requests/Security/IpUnbanRequest.php +++ b/app/Http/Requests/Security/IpUnbanRequest.php @@ -28,7 +28,7 @@ class IpUnbanRequest extends ApiFormRequest $ip = $this->input('ip'); $all = filter_var($this->input('all'), FILTER_VALIDATE_BOOLEAN); - if (! $all && ! $id && ! $ip) { + if (!$all && !$id && !$ip) { $validator->errors()->add('id', 'Either id, ip, or all=true is required.'); } }); diff --git a/app/Http/Resources/Admin/AdminNotificationAlertsResource.php b/app/Http/Resources/Admin/AdminNotificationAlertsResource.php index cf371d8a..0f0a1dc6 100644 --- a/app/Http/Resources/Admin/AdminNotificationAlertsResource.php +++ b/app/Http/Resources/Admin/AdminNotificationAlertsResource.php @@ -16,4 +16,4 @@ class AdminNotificationAlertsResource extends JsonResource 'table_ready' => (bool) ($this['table_ready'] ?? false), ]; } -} +} \ No newline at end of file diff --git a/app/Http/Resources/Admin/PrintRecipientsResource.php b/app/Http/Resources/Admin/PrintRecipientsResource.php index db8dd1e4..867d2dc8 100644 --- a/app/Http/Resources/Admin/PrintRecipientsResource.php +++ b/app/Http/Resources/Admin/PrintRecipientsResource.php @@ -15,4 +15,4 @@ class PrintRecipientsResource extends JsonResource 'table_ready' => (bool) ($this['table_ready'] ?? false), ]; } -} +} \ No newline at end of file diff --git a/app/Http/Resources/Admin/Progress/ProgressGroupResource.php b/app/Http/Resources/Admin/Progress/ProgressGroupResource.php index 8b1c25d9..e768b766 100644 --- a/app/Http/Resources/Admin/Progress/ProgressGroupResource.php +++ b/app/Http/Resources/Admin/Progress/ProgressGroupResource.php @@ -19,4 +19,4 @@ class ProgressGroupResource extends JsonResource 'reports' => $reports, // keyed by subject for compatibility ]; } -} +} \ No newline at end of file diff --git a/app/Http/Resources/Admin/Progress/ProgressReportDetailResource.php b/app/Http/Resources/Admin/Progress/ProgressReportDetailResource.php index 40f31809..67db6e36 100644 --- a/app/Http/Resources/Admin/Progress/ProgressReportDetailResource.php +++ b/app/Http/Resources/Admin/Progress/ProgressReportDetailResource.php @@ -15,4 +15,4 @@ class ProgressReportDetailResource extends JsonResource 'subject_sections' => $this['subject_sections'] ?? [], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Resources/Admin/TeacherSubmissionReportResource.php b/app/Http/Resources/Admin/TeacherSubmissionReportResource.php index 47b673f9..17a1b776 100644 --- a/app/Http/Resources/Admin/TeacherSubmissionReportResource.php +++ b/app/Http/Resources/Admin/TeacherSubmissionReportResource.php @@ -22,4 +22,4 @@ class TeacherSubmissionReportResource extends JsonResource ], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Resources/Attendance/AdminAttendanceResource.php b/app/Http/Resources/Attendance/AdminAttendanceResource.php index 9241743e..c48f9509 100644 --- a/app/Http/Resources/Attendance/AdminAttendanceResource.php +++ b/app/Http/Resources/Attendance/AdminAttendanceResource.php @@ -16,4 +16,4 @@ class AdminAttendanceResource extends JsonResource 'admins_grid' => $this['admins_grid'] ?? [], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Resources/Attendance/DailyAttendanceResource.php b/app/Http/Resources/Attendance/DailyAttendanceResource.php index ef3f5e94..ce0a40ad 100644 --- a/app/Http/Resources/Attendance/DailyAttendanceResource.php +++ b/app/Http/Resources/Attendance/DailyAttendanceResource.php @@ -25,4 +25,4 @@ class DailyAttendanceResource extends JsonResource 'current_admin_name' => $this['currentAdminName'] ?? null, ]; } -} +} \ No newline at end of file diff --git a/app/Http/Resources/Attendance/TeacherAttendanceFormResource.php b/app/Http/Resources/Attendance/TeacherAttendanceFormResource.php index f6b1d306..0e72ddfc 100644 --- a/app/Http/Resources/Attendance/TeacherAttendanceFormResource.php +++ b/app/Http/Resources/Attendance/TeacherAttendanceFormResource.php @@ -9,7 +9,7 @@ class TeacherAttendanceFormResource extends JsonResource { public function toArray(Request $request): array { - $enable = (int) ($this['enable_attendance'] ?? 0); + $enable = (int)($this['enable_attendance'] ?? 0); $res = $this->resource; $hasCanEditKey = is_array($res) && array_key_exists('can_edit', $res); @@ -29,4 +29,4 @@ class TeacherAttendanceFormResource extends JsonResource 'locked_by_student' => $this['locked_by_student'] ?? [], ]; } -} +} \ No newline at end of file diff --git a/app/Http/Resources/Attendance/TeacherGridResource.php b/app/Http/Resources/Attendance/TeacherGridResource.php index 313ab743..3daa03bf 100644 --- a/app/Http/Resources/Attendance/TeacherGridResource.php +++ b/app/Http/Resources/Attendance/TeacherGridResource.php @@ -16,7 +16,7 @@ class TeacherGridResource extends JsonResource 'class_section_id' => $this['class_section_id'] ?? null, 'sections' => $this['sections'] ?? [], 'grid' => $this['grid'] ?? [], - 'locked' => (bool) ($this['locked'] ?? false), + 'locked' => (bool)($this['locked'] ?? false), ]; } -} +} \ No newline at end of file diff --git a/app/Http/Resources/ClassProgress/ClassProgressGroupCollection.php b/app/Http/Resources/ClassProgress/ClassProgressGroupCollection.php index 8ba9c2df..daa20591 100644 --- a/app/Http/Resources/ClassProgress/ClassProgressGroupCollection.php +++ b/app/Http/Resources/ClassProgress/ClassProgressGroupCollection.php @@ -23,9 +23,9 @@ class ClassProgressGroupCollection extends ResourceCollection continue; } - $key = $sectionId.'|'.$weekStart; + $key = $sectionId . '|' . $weekStart; - if (! isset($groups[$key])) { + if (!isset($groups[$key])) { $groups[$key] = [ 'week_start' => $weekStart, 'week_end' => $report->week_end?->format('Y-m-d'), diff --git a/app/Http/Resources/Events/EventChargeResource.php b/app/Http/Resources/Events/EventChargeResource.php index 9b062c88..d9622d53 100644 --- a/app/Http/Resources/Events/EventChargeResource.php +++ b/app/Http/Resources/Events/EventChargeResource.php @@ -14,9 +14,9 @@ class EventChargeResource extends JsonResource 'event_id' => (int) ($this->event_id ?? 0), 'event_name' => $this->event_name ?? null, 'parent_id' => (int) ($this->parent_id ?? 0), - 'parent_name' => trim(($this->parent_firstname ?? '').' '.($this->parent_lastname ?? '')), + 'parent_name' => trim(($this->parent_firstname ?? '') . ' ' . ($this->parent_lastname ?? '')), 'student_id' => (int) ($this->student_id ?? 0), - 'student_name' => trim(($this->student_firstname ?? '').' '.($this->student_lastname ?? '')), + 'student_name' => trim(($this->student_firstname ?? '') . ' ' . ($this->student_lastname ?? '')), 'participation' => $this->getRawOriginal('participation') ?? $this->participation, 'charged' => (float) ($this->getRawOriginal('charged') ?? $this->charged ?? 0), 'school_year' => $this->school_year, diff --git a/app/Http/Resources/Messaging/MessageCollection.php b/app/Http/Resources/Messaging/MessageCollection.php index 7b5c7ad9..3703c1a4 100644 --- a/app/Http/Resources/Messaging/MessageCollection.php +++ b/app/Http/Resources/Messaging/MessageCollection.php @@ -8,7 +8,7 @@ class MessageCollection extends ResourceCollection { public function with($request): array { - if (! method_exists($this->resource, 'total')) { + if (!method_exists($this->resource, 'total')) { return []; } diff --git a/app/Http/Resources/Messaging/MessageResource.php b/app/Http/Resources/Messaging/MessageResource.php index 3c0c0478..3acb8ac3 100644 --- a/app/Http/Resources/Messaging/MessageResource.php +++ b/app/Http/Resources/Messaging/MessageResource.php @@ -24,8 +24,8 @@ class MessageResource extends JsonResource 'status' => $this->status ?? null, 'semester' => $this->semester ?? null, 'school_year' => $this->school_year ?? null, - 'sender_name' => $this->sender ? trim($this->sender->firstname.' '.$this->sender->lastname) : null, - 'recipient_name' => $this->recipient ? trim($this->recipient->firstname.' '.$this->recipient->lastname) : null, + 'sender_name' => $this->sender ? trim($this->sender->firstname . ' ' . $this->sender->lastname) : null, + 'recipient_name' => $this->recipient ? trim($this->recipient->firstname . ' ' . $this->recipient->lastname) : null, ]; } } diff --git a/app/Http/Resources/Payments/PaymentNotificationLogResource.php b/app/Http/Resources/Payments/PaymentNotificationLogResource.php index bec8d35a..78b5a744 100644 --- a/app/Http/Resources/Payments/PaymentNotificationLogResource.php +++ b/app/Http/Resources/Payments/PaymentNotificationLogResource.php @@ -10,7 +10,7 @@ class PaymentNotificationLogResource extends JsonResource public function toArray(Request $request): array { $parent = $this->resource->parent ?? null; - $parentName = $parent ? trim(($parent->firstname ?? '').' '.($parent->lastname ?? '')) : null; + $parentName = $parent ? trim(($parent->firstname ?? '') . ' ' . ($parent->lastname ?? '')) : null; return [ 'id' => (int) ($this->resource->id ?? 0), diff --git a/app/Http/Resources/Promotions/StudentPromotionResource.php b/app/Http/Resources/Promotions/StudentPromotionResource.php index c0711435..ec6455c0 100644 --- a/app/Http/Resources/Promotions/StudentPromotionResource.php +++ b/app/Http/Resources/Promotions/StudentPromotionResource.php @@ -19,7 +19,6 @@ class StudentPromotionResource extends JsonResource if (is_array($r)) { return $r[$key] ?? $default; } - return $r->{$key} ?? $default; }; diff --git a/app/Http/Resources/Reimbursements/ReimbursementRecipientResource.php b/app/Http/Resources/Reimbursements/ReimbursementRecipientResource.php index 0f16fbff..70f2bfd4 100644 --- a/app/Http/Resources/Reimbursements/ReimbursementRecipientResource.php +++ b/app/Http/Resources/Reimbursements/ReimbursementRecipientResource.php @@ -12,7 +12,7 @@ class ReimbursementRecipientResource extends JsonResource $id = (int) ($this->resource['id'] ?? 0); $first = $this->resource['firstname'] ?? ''; $last = $this->resource['lastname'] ?? ''; - $name = trim($first.' '.$last); + $name = trim($first . ' ' . $last); return [ 'id' => $id, diff --git a/app/Http/Resources/Staff/StaffCollection.php b/app/Http/Resources/Staff/StaffCollection.php index 71532432..7eb263e1 100644 --- a/app/Http/Resources/Staff/StaffCollection.php +++ b/app/Http/Resources/Staff/StaffCollection.php @@ -15,7 +15,7 @@ class StaffCollection extends ResourceCollection public function with($request): array { - if (! method_exists($this->resource, 'total')) { + if (!method_exists($this->resource, 'total')) { return []; } diff --git a/app/Http/Resources/Support/SupportRequestCollection.php b/app/Http/Resources/Support/SupportRequestCollection.php index 3066c892..fda04237 100644 --- a/app/Http/Resources/Support/SupportRequestCollection.php +++ b/app/Http/Resources/Support/SupportRequestCollection.php @@ -15,7 +15,7 @@ class SupportRequestCollection extends ResourceCollection public function with($request): array { - if (! method_exists($this->resource, 'total')) { + if (!method_exists($this->resource, 'total')) { return []; } diff --git a/app/Http/Resources/System/NavItemResource.php b/app/Http/Resources/System/NavItemResource.php index 60360056..67b0d82b 100644 --- a/app/Http/Resources/System/NavItemResource.php +++ b/app/Http/Resources/System/NavItemResource.php @@ -20,7 +20,7 @@ class NavItemResource extends JsonResource 'target' => $item['target'] ?? null, 'sort_order' => (int) ($item['sort_order'] ?? 0), 'is_enabled' => (int) ($item['is_enabled'] ?? 0), - 'children' => ! empty($item['children']) + 'children' => !empty($item['children']) ? NavItemResource::collection($item['children']) : [], ]; diff --git a/app/Http/Resources/TeacherSubmissionRowResource.php b/app/Http/Resources/TeacherSubmissionRowResource.php index 9c7e1ef9..c6c15918 100644 --- a/app/Http/Resources/TeacherSubmissionRowResource.php +++ b/app/Http/Resources/TeacherSubmissionRowResource.php @@ -24,4 +24,4 @@ class TeacherSubmissionRowResource extends JsonResource 'missing_items' => $this['missing_items'] ?? [], ]; } -} +} \ No newline at end of file diff --git a/app/Libraries/StaffTimeOffLinkService.php b/app/Libraries/StaffTimeOffLinkService.php index b46e8ed2..e44fc38d 100644 --- a/app/Libraries/StaffTimeOffLinkService.php +++ b/app/Libraries/StaffTimeOffLinkService.php @@ -6,7 +6,9 @@ use App\Services\Staff\StaffTimeOffLinkService as StaffTimeOffLinkTokenService; class StaffTimeOffLinkService { - public function __construct(private StaffTimeOffLinkTokenService $service = new StaffTimeOffLinkTokenService) {} + public function __construct(private StaffTimeOffLinkTokenService $service = new StaffTimeOffLinkTokenService()) + { + } public function createToken(array $payload): string { diff --git a/app/Listeners/AttendanceConsequenceListener.php b/app/Listeners/AttendanceConsequenceListener.php index b8f56b73..1238751c 100644 --- a/app/Listeners/AttendanceConsequenceListener.php +++ b/app/Listeners/AttendanceConsequenceListener.php @@ -6,7 +6,9 @@ use App\Services\Attendance\AttendanceConsequenceService; class AttendanceConsequenceListener { - public function __construct(private AttendanceConsequenceService $service) {} + public function __construct(private AttendanceConsequenceService $service) + { + } public function followUp(array $payload): void { diff --git a/app/Listeners/BelowSixtyEmailListener.php b/app/Listeners/BelowSixtyEmailListener.php index fe021b58..0e9c54b9 100644 --- a/app/Listeners/BelowSixtyEmailListener.php +++ b/app/Listeners/BelowSixtyEmailListener.php @@ -6,7 +6,9 @@ use App\Services\Grading\BelowSixtyEmailService; class BelowSixtyEmailListener { - public function __construct(private BelowSixtyEmailService $service) {} + public function __construct(private BelowSixtyEmailService $service) + { + } public function handle(array $payload): void { diff --git a/app/Listeners/DeleteUnverifiedUserListener.php b/app/Listeners/DeleteUnverifiedUserListener.php index 4108eed6..e84bb7f6 100644 --- a/app/Listeners/DeleteUnverifiedUserListener.php +++ b/app/Listeners/DeleteUnverifiedUserListener.php @@ -7,7 +7,9 @@ use App\Services\Users\DeleteUnverifiedUserService; class DeleteUnverifiedUserListener { - public function __construct(private DeleteUnverifiedUserService $service) {} + public function __construct(private DeleteUnverifiedUserService $service) + { + } public function handle(DeleteUnverifiedUser $event): void { diff --git a/app/Listeners/SchoolEventListener.php b/app/Listeners/SchoolEventListener.php index 2ca41471..3ed583d5 100644 --- a/app/Listeners/SchoolEventListener.php +++ b/app/Listeners/SchoolEventListener.php @@ -12,7 +12,8 @@ class SchoolEventListener private EnrollmentEventService $enrollment, private PaymentEventService $payments, private AccountEventService $accounts - ) {} + ) { + } public function handleAdmissionUnderReview(array $data, array $studentdata): void { diff --git a/app/Listeners/WhatsappInviteListener.php b/app/Listeners/WhatsappInviteListener.php index f7925cd3..da7c4409 100644 --- a/app/Listeners/WhatsappInviteListener.php +++ b/app/Listeners/WhatsappInviteListener.php @@ -7,7 +7,9 @@ use App\Services\Whatsapp\WhatsappInviteEmailService; class WhatsappInviteListener { - public function __construct(private WhatsappInviteEmailService $service) {} + public function __construct(private WhatsappInviteEmailService $service) + { + } public function handle(WhatsappInvitesSend $event): void { diff --git a/app/Mail/TeacherSubmissionReminderMail.php b/app/Mail/TeacherSubmissionReminderMail.php index 7161e567..a1d71a3e 100644 --- a/app/Mail/TeacherSubmissionReminderMail.php +++ b/app/Mail/TeacherSubmissionReminderMail.php @@ -14,7 +14,8 @@ class TeacherSubmissionReminderMail extends Mailable public function __construct( protected string $subjectLine, protected string $htmlBody - ) {} + ) { + } public function build(): self { diff --git a/app/Models/AdditionalCharge.php b/app/Models/AdditionalCharge.php index 91e5f242..1c50fd08 100644 --- a/app/Models/AdditionalCharge.php +++ b/app/Models/AdditionalCharge.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; class AdditionalCharge extends BaseModel @@ -27,10 +28,10 @@ class AdditionalCharge extends BaseModel ]; protected $casts = [ - 'parent_id' => 'integer', + 'parent_id' => 'integer', 'invoice_id' => 'integer', - 'amount' => 'decimal:2', // adjust if you store more precision - 'due_date' => 'date', // if due_date is DATE/DATETIME + 'amount' => 'decimal:2', // adjust if you store more precision + 'due_date' => 'date', // if due_date is DATE/DATETIME 'created_by' => 'integer', ]; @@ -119,7 +120,7 @@ class AdditionalCharge extends BaseModel $affected = static::query() ->whereIn('id', $ids) ->update([ - 'status' => 'applied', + 'status' => 'applied', 'invoice_id' => $invoiceId, ]); @@ -156,18 +157,18 @@ class AdditionalCharge extends BaseModel $query->where('additional_charges.semester', $semFilter); } - if (! empty($status)) { + if (!empty($status)) { $query->where('additional_charges.status', $status); } - if (! empty($q)) { + if (!empty($q)) { $term = trim($q); $query->where(function ($w) use ($term) { $w->where('additional_charges.title', 'like', "%{$term}%") - ->orWhere('additional_charges.description', 'like', "%{$term}%") - ->orWhere('users.firstname', 'like', "%{$term}%") - ->orWhere('users.lastname', 'like', "%{$term}%") - ->orWhere('invoices.invoice_number', 'like', "%{$term}%"); + ->orWhere('additional_charges.description', 'like', "%{$term}%") + ->orWhere('users.firstname', 'like', "%{$term}%") + ->orWhere('users.lastname', 'like', "%{$term}%") + ->orWhere('invoices.invoice_number', 'like', "%{$term}%"); }); } diff --git a/app/Models/AdminNotificationSubject.php b/app/Models/AdminNotificationSubject.php index 747ccf6f..469a54c3 100644 --- a/app/Models/AdminNotificationSubject.php +++ b/app/Models/AdminNotificationSubject.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class AdminNotificationSubject extends BaseModel { protected $table = 'admin_notification_subjects'; @@ -14,8 +16,7 @@ class AdminNotificationSubject extends BaseModel ]; // legacy uses created_at / updated_at - public $timestamps = true; - + public $timestamps = true; protected $casts = [ 'admin_id' => 'integer', ]; @@ -25,4 +26,4 @@ class AdminNotificationSubject extends BaseModel { return $this->belongsTo(User::class, 'admin_id'); } -} +} \ No newline at end of file diff --git a/app/Models/AttendanceCommentTemplate.php b/app/Models/AttendanceCommentTemplate.php index 96551754..bfd0df1b 100644 --- a/app/Models/AttendanceCommentTemplate.php +++ b/app/Models/AttendanceCommentTemplate.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class AttendanceCommentTemplate extends BaseModel { protected $table = 'attendance_comment_template'; @@ -41,4 +43,4 @@ class AttendanceCommentTemplate extends BaseModel { return $q->where('is_active', 1); } -} +} \ No newline at end of file diff --git a/app/Models/AttendanceData.php b/app/Models/AttendanceData.php index a5e55d94..51770c6c 100644 --- a/app/Models/AttendanceData.php +++ b/app/Models/AttendanceData.php @@ -2,13 +2,13 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; class AttendanceData extends BaseModel { protected $table = 'attendance_data'; - public $timestamps = true; // uses created_at / updated_at protected $fillable = [ @@ -30,12 +30,12 @@ class AttendanceData extends BaseModel ]; protected $casts = [ - 'class_id' => 'integer', + 'class_id' => 'integer', 'class_section_id' => 'integer', - 'school_id' => 'integer', - 'student_id' => 'integer', - 'modified_by' => 'integer', - 'date' => 'datetime', // ✅ DATETIME column + 'school_id' => 'integer', + 'student_id' => 'integer', + 'modified_by' => 'integer', + 'date' => 'datetime', // ✅ DATETIME column ]; /* ========================= @@ -59,7 +59,6 @@ class AttendanceData extends BaseModel $day = substr($day, 0, 10); // YYYY-MM-DD $start = Carbon::parse($day)->startOfDay(); $endEx = Carbon::parse($day)->addDay()->startOfDay(); // exclusive - return [$start, $endEx]; } @@ -88,7 +87,6 @@ class AttendanceData extends BaseModel public static function updateAttendance(int $attendanceId, array $data): bool { $affected = static::query()->whereKey($attendanceId)->update($data); - return $affected >= 0; } @@ -115,7 +113,7 @@ class AttendanceData extends BaseModel $q = static::query(); static::applyReportedFilter($q); - [$start] = static::dayRange($startDate); + [$start, ] = static::dayRange($startDate); if ($endDate) { [, $endEx] = static::dayRange($endDate); // end exclusive of next day @@ -136,19 +134,13 @@ class AttendanceData extends BaseModel ->where('date', '>=', $start) ->where('date', '<', $endEx) ->where(function ($w) { - $w->whereIn(DB::raw('UPPER(TRIM(status))'), ['ABSENT', 'ABS', 'A']) - ->orWhereRaw("UPPER(TRIM(status)) LIKE 'ABS%'"); + $w->whereIn(DB::raw("UPPER(TRIM(status))"), ['ABSENT', 'ABS', 'A']) + ->orWhereRaw("UPPER(TRIM(status)) LIKE 'ABS%'"); }); - if ($classSectionId !== null) { - $q->where('class_section_id', $classSectionId); - } - if ($schoolYear !== null) { - $q->where('school_year', $schoolYear); - } - if ($semester !== null) { - $q->where('semester', $semester); - } + if ($classSectionId !== null) $q->where('class_section_id', $classSectionId); + if ($schoolYear !== null) $q->where('school_year', $schoolYear); + if ($semester !== null) $q->where('semester', $semester); return $q->get(); } @@ -161,19 +153,13 @@ class AttendanceData extends BaseModel ->where('date', '>=', $start) ->where('date', '<', $endEx) ->where(function ($w) { - $w->whereIn(DB::raw('UPPER(TRIM(status))'), ['LATE', 'L']) - ->orWhereRaw("UPPER(TRIM(status)) LIKE 'LATE%'"); + $w->whereIn(DB::raw("UPPER(TRIM(status))"), ['LATE', 'L']) + ->orWhereRaw("UPPER(TRIM(status)) LIKE 'LATE%'"); }); - if ($classSectionId !== null) { - $q->where('class_section_id', $classSectionId); - } - if ($schoolYear !== null) { - $q->where('school_year', $schoolYear); - } - if ($semester !== null) { - $q->where('semester', $semester); - } + if ($classSectionId !== null) $q->where('class_section_id', $classSectionId); + if ($schoolYear !== null) $q->where('school_year', $schoolYear); + if ($semester !== null) $q->where('semester', $semester); return $q->get(); } @@ -185,8 +171,8 @@ class AttendanceData extends BaseModel ->where('school_year', $schoolYear) ->where('semester', $semester) ->where(function ($w) { - $w->whereIn(DB::raw('UPPER(TRIM(status))'), ['ABSENT', 'ABS', 'A']) - ->orWhereRaw("UPPER(TRIM(status)) LIKE 'ABS%'"); + $w->whereIn(DB::raw("UPPER(TRIM(status))"), ['ABSENT', 'ABS', 'A']) + ->orWhereRaw("UPPER(TRIM(status)) LIKE 'ABS%'"); }) ->orderByDesc('date') ->get(); @@ -199,26 +185,22 @@ class AttendanceData extends BaseModel public static function getStudentAttendance( int $studentId, ?string $startDate = null, - ?string $endDate = null, + ?string $endDate = null, ?string $schoolYear = null, - ?string $semester = null + ?string $semester = null ) { $q = static::query()->where('student_id', $studentId); - if (! empty($startDate)) { - [$start] = static::dayRange($startDate); + if (!empty($startDate)) { + [$start, ] = static::dayRange($startDate); $q->where('date', '>=', $start); } - if (! empty($endDate)) { + if (!empty($endDate)) { [, $endEx] = static::dayRange($endDate); $q->where('date', '<', $endEx); } - if (! empty($schoolYear)) { - $q->where('school_year', $schoolYear); - } - if (! empty($semester)) { - $q->where('semester', $semester); - } + if (!empty($schoolYear)) $q->where('school_year', $schoolYear); + if (!empty($semester)) $q->where('semester', $semester); return $q->orderByDesc('date')->get(); } @@ -243,13 +225,13 @@ class AttendanceData extends BaseModel public static function unreportedTermRows(array $studentIds, string $schoolYear, ?string $semester) { $q = static::query() - ->select(['id', 'student_id', 'class_id', 'class_section_id', 'date', 'status', 'reason', 'school_year', 'semester', 'is_reported']) + ->select(['id','student_id','class_id','class_section_id','date','status','reason','school_year','semester','is_reported']) ->where('school_year', $schoolYear); if ($semester !== null && $semester !== '') { $q->where('semester', $semester); } - if (! empty($studentIds)) { + if (!empty($studentIds)) { $q->whereIn('student_id', array_map('intval', $studentIds)); } @@ -265,30 +247,26 @@ class AttendanceData extends BaseModel public static function getUnreportedAbsencesAndLates(?string $schoolYear = null, ?string $semester = null): array { $q = static::query() - ->select(['id', 'student_id', 'class_id', 'class_section_id', 'date', 'status', 'reason', 'school_year', 'semester', 'is_reported']); + ->select(['id','student_id','class_id','class_section_id','date','status','reason','school_year','semester','is_reported']); static::applyUnreportedFilter($q); // Not notified yet: supports 0/'0'/NULL and string enums like 'yes' $q->where(function ($w) { $w->whereNull('is_notified') - ->orWhere('is_notified', 0) - ->orWhere('is_notified', '0') - ->orWhereRaw("LOWER(TRIM(COALESCE(is_notified, ''))) != 'yes'"); + ->orWhere('is_notified', 0) + ->orWhere('is_notified', '0') + ->orWhereRaw("LOWER(TRIM(COALESCE(is_notified, ''))) != 'yes'"); }); - if (! empty($schoolYear)) { - $q->where('school_year', $schoolYear); - } - if (! empty($semester)) { - $q->where('semester', $semester); - } + if (!empty($schoolYear)) $q->where('school_year', $schoolYear); + if (!empty($semester)) $q->where('semester', $semester); // Status filter: exact + prefixes (ABS_3, LATE_2, etc.) $q->where(function ($w) { - $w->whereIn(DB::raw('UPPER(TRIM(status))'), ['ABS', 'ABSENT', 'LATE', 'A', 'L']) - ->orWhereRaw("UPPER(TRIM(status)) LIKE 'ABS%'") - ->orWhereRaw("UPPER(TRIM(status)) LIKE 'LATE%'"); + $w->whereIn(DB::raw("UPPER(TRIM(status))"), ['ABS','ABSENT','LATE','A','L']) + ->orWhereRaw("UPPER(TRIM(status)) LIKE 'ABS%'") + ->orWhereRaw("UPPER(TRIM(status)) LIKE 'LATE%'"); }); $rows = $q->orderBy('student_id')->orderByDesc('date')->get()->toArray(); @@ -297,27 +275,27 @@ class AttendanceData extends BaseModel foreach ($rows as $r) { $sid = (int) ($r['student_id'] ?? 0); - if (! isset($out[$sid])) { + if (!isset($out[$sid])) { $out[$sid] = [ 'absences' => [], - 'lates' => [], - 'counts' => ['absences' => 0, 'lates' => 0, 'total' => 0], + 'lates' => [], + 'counts' => ['absences' => 0, 'lates' => 0, 'total' => 0], ]; } - $st = strtoupper(trim((string) ($r['status'] ?? ''))); - $isAbs = ($st === 'ABS' || $st === 'ABSENT' || $st === 'A' || str_starts_with($st, 'ABS')); + $st = strtoupper(trim((string)($r['status'] ?? ''))); + $isAbs = ($st === 'ABS' || $st === 'ABSENT' || $st === 'A' || str_starts_with($st, 'ABS')); $isLate = ($st === 'LATE' || $st === 'L' || str_starts_with($st, 'LATE')); $rec = [ - 'id' => $r['id'] ?? null, - 'date' => $r['date'] ?? null, - 'status' => $r['status'] ?? null, - 'reason' => $r['reason'] ?? null, - 'class_id' => $r['class_id'] ?? null, + 'id' => $r['id'] ?? null, + 'date' => $r['date'] ?? null, + 'status' => $r['status'] ?? null, + 'reason' => $r['reason'] ?? null, + 'class_id' => $r['class_id'] ?? null, 'class_section_id' => $r['class_section_id'] ?? null, - 'school_year' => $r['school_year'] ?? null, - 'semester' => $r['semester'] ?? null, + 'school_year' => $r['school_year'] ?? null, + 'semester' => $r['semester'] ?? null, ]; if ($isAbs) { @@ -351,16 +329,12 @@ class AttendanceData extends BaseModel ->where('date', '>=', $start) ->where('date', '<', $endEx); - if (! empty($semester)) { - $q->where('semester', $semester); - } - if (! empty($schoolYear)) { - $q->where('school_year', $schoolYear); - } + if (!empty($semester)) $q->where('semester', $semester); + if (!empty($schoolYear)) $q->where('school_year', $schoolYear); $affected = $q->update([ 'is_notified' => 'yes', - 'updated_at' => now(), + 'updated_at' => now(), ]); return $affected >= 0; @@ -375,20 +349,14 @@ class AttendanceData extends BaseModel return is_string($d) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $d); }))); - if (empty($dates)) { - return true; - } + if (empty($dates)) return true; $q = static::query() ->where('student_id', $studentId) ->whereRaw("LOWER(TRIM(status)) IN ('absent','late')"); - if (! empty($semester)) { - $q->where('semester', $semester); - } - if (! empty($schoolYear)) { - $q->where('school_year', $schoolYear); - } + if (!empty($semester)) $q->where('semester', $semester); + if (!empty($schoolYear)) $q->where('school_year', $schoolYear); // OR day ranges instead of DATE(date) $q->where(function ($w) use ($dates) { @@ -402,17 +370,13 @@ class AttendanceData extends BaseModel }); $payload = [ - 'updated_at' => now(), + 'updated_at' => now(), 'is_notified' => 'yes', ]; $cols = static::reportedColumns(); - if (! empty($cols['is_reported'])) { - $payload['is_reported'] = 'yes'; - } - if (! empty($cols['reported'])) { - $payload['reported'] = 1; - } + if (!empty($cols['is_reported'])) $payload['is_reported'] = 'yes'; + if (!empty($cols['reported'])) $payload['reported'] = 1; $affected = $q->update($payload); @@ -430,9 +394,7 @@ class AttendanceData extends BaseModel ?string $semester = null, ?string $schoolYear = null ): array { - if ($studentId <= 0 || empty($statuses)) { - return []; - } + if ($studentId <= 0 || empty($statuses)) return []; $statuses = array_map('strtolower', $statuses); @@ -441,7 +403,7 @@ class AttendanceData extends BaseModel : now()->toDateString(); $startDay = Carbon::parse($day)->subDays(max(0, $lookbackDays))->toDateString(); - [$start] = static::dayRange($startDay); + [$start, ] = static::dayRange($startDay); [, $endEx] = static::dayRange($day); $q = static::query() @@ -449,21 +411,17 @@ class AttendanceData extends BaseModel ->where('student_id', $studentId) ->where('date', '>=', $start) ->where('date', '<', $endEx) - ->whereIn(DB::raw('LOWER(TRIM(status))'), $statuses); + ->whereIn(DB::raw("LOWER(TRIM(status))"), $statuses); static::applyUnreportedFilter($q); - if (! empty($semester)) { - $q->where('semester', $semester); - } - if (! empty($schoolYear)) { - $q->where('school_year', $schoolYear); - } + if (!empty($semester)) $q->where('semester', $semester); + if (!empty($schoolYear)) $q->where('school_year', $schoolYear); $rows = $q->orderByDesc('date')->pluck('date')->all(); return array_values(array_unique(array_map(static function ($d) { - return substr((string) $d, 0, 10); // YYYY-MM-DD + return substr((string)$d, 0, 10); // YYYY-MM-DD }, $rows))); } @@ -474,15 +432,13 @@ class AttendanceData extends BaseModel private static function reportedColumns(): array { static $cache = null; - if ($cache !== null) { - return $cache; - } + if ($cache !== null) return $cache; $table = (new static)->getTable(); $cache = [ 'is_reported' => static::columnExists($table, 'is_reported'), - 'reported' => static::columnExists($table, 'reported'), + 'reported' => static::columnExists($table, 'reported'), ]; return $cache; @@ -508,16 +464,16 @@ class AttendanceData extends BaseModel { $cols = static::reportedColumns(); - if (! empty($cols['is_reported'])) { + if (!empty($cols['is_reported'])) { $q->where(function ($w) { $w->whereNull('is_reported') - ->orWhere('is_reported', 0) - ->orWhere('is_reported', '0') - ->orWhereRaw("LOWER(TRIM(COALESCE(is_reported, ''))) = 'no'"); + ->orWhere('is_reported', 0) + ->orWhere('is_reported', '0') + ->orWhereRaw("LOWER(TRIM(COALESCE(is_reported, ''))) = 'no'"); }); } - if (! empty($cols['reported'])) { + if (!empty($cols['reported'])) { $q->whereRaw("(LOWER(TRIM(COALESCE(reported, ''))) NOT IN ('yes','1','true','y','on'))"); } } @@ -529,8 +485,8 @@ class AttendanceData extends BaseModel { $q->where(function ($w) { $w->where('is_reported', 1) - ->orWhere('is_reported', '1') - ->orWhereRaw("LOWER(TRIM(COALESCE(is_reported, ''))) = 'yes'"); + ->orWhere('is_reported', '1') + ->orWhereRaw("LOWER(TRIM(COALESCE(is_reported, ''))) = 'yes'"); }); } } diff --git a/app/Models/AttendanceDay.php b/app/Models/AttendanceDay.php index 4c82dfea..b9c00c22 100644 --- a/app/Models/AttendanceDay.php +++ b/app/Models/AttendanceDay.php @@ -2,8 +2,9 @@ namespace App\Models; -use Illuminate\Database\QueryException; +use App\Models\BaseModel; use Illuminate\Support\Carbon; +use Illuminate\Database\QueryException; class AttendanceDay extends BaseModel { @@ -38,20 +39,20 @@ class AttendanceDay extends BaseModel protected $casts = [ 'class_section_id' => 'integer', - 'submitted_by' => 'integer', - 'published_by' => 'integer', - 'reopened_by' => 'integer', + 'submitted_by' => 'integer', + 'published_by' => 'integer', + 'reopened_by' => 'integer', // If these are DATETIME columns: - 'submitted_at' => 'datetime', - 'published_at' => 'datetime', - 'auto_publish_at' => 'datetime', - 'reopened_at' => 'datetime', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'submitted_at' => 'datetime', + 'published_at' => 'datetime', + 'auto_publish_at' => 'datetime', + 'reopened_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', // If date is stored as DATE string; if it's DATETIME, change to 'datetime' - 'date' => 'date', + 'date' => 'date', ]; /* ========================= @@ -74,15 +75,11 @@ class AttendanceDay extends BaseModel ->whereDate('date', $date) ->where(function ($w) { $w->where('status', 'published') - ->orWhere('status', 'finalized'); // legacy + ->orWhere('status', 'finalized'); // legacy }); - if ($semester !== null) { - $q->where('semester', $semester); - } - if ($schoolYear !== null) { - $q->where('school_year', $schoolYear); - } + if ($semester !== null) $q->where('semester', $semester); + if ($schoolYear !== null) $q->where('school_year', $schoolYear); return $q->exists(); } @@ -116,9 +113,7 @@ class AttendanceDay extends BaseModel int $userId = 0 ): self { $row = static::findBySectionDate($classSectionId, $date, $semester, $schoolYear); - if ($row) { - return $row; - } + if ($row) return $row; $now = now(); $normalizedDate = Carbon::parse($date)->toDateString(); @@ -126,27 +121,25 @@ class AttendanceDay extends BaseModel try { return static::create([ 'class_section_id' => $classSectionId, - 'date' => $normalizedDate, - 'status' => 'draft', - 'submitted_by' => null, - 'submitted_at' => null, - 'published_by' => null, - 'published_at' => null, - 'auto_publish_at' => null, - 'reopened_by' => null, - 'reopened_at' => null, - 'reopen_reason' => null, - 'semester' => $semester, - 'school_year' => $schoolYear, - 'created_at' => $now, - 'updated_at' => $now, + 'date' => $normalizedDate, + 'status' => 'draft', + 'submitted_by' => null, + 'submitted_at' => null, + 'published_by' => null, + 'published_at' => null, + 'auto_publish_at' => null, + 'reopened_by' => null, + 'reopened_at' => null, + 'reopen_reason' => null, + 'semester' => $semester, + 'school_year' => $schoolYear, + 'created_at' => $now, + 'updated_at' => $now, ]); } catch (QueryException $e) { // Race: someone inserted same unique key. $row = static::findBySectionDate($classSectionId, $date, $semester, $schoolYear); - if ($row) { - return $row; - } + if ($row) return $row; throw $e; } } @@ -167,10 +160,10 @@ class AttendanceDay extends BaseModel $now = now(); $payload = [ - 'status' => 'submitted', + 'status' => 'submitted', 'submitted_by' => $userId, 'submitted_at' => $now, - 'updated_at' => $now, + 'updated_at' => $now, ]; if ($autoPublishAt !== null) { @@ -188,10 +181,10 @@ class AttendanceDay extends BaseModel $now = now(); return static::query()->whereKey($this->id)->update([ - 'status' => 'published', + 'status' => 'published', 'published_by' => $userId, 'published_at' => $now, - 'updated_at' => $now, + 'updated_at' => $now, ]) >= 0; } @@ -200,18 +193,18 @@ class AttendanceDay extends BaseModel */ public function reopen(int $userId, string $toStatus = 'draft', ?string $reason = null): bool { - if (! in_array($toStatus, ['draft', 'submitted'], true)) { + if (!in_array($toStatus, ['draft', 'submitted'], true)) { throw new \InvalidArgumentException('toStatus must be "draft" or "submitted".'); } $now = now(); return static::query()->whereKey($this->id)->update([ - 'status' => $toStatus, - 'reopened_by' => $userId, - 'reopened_at' => $now, + 'status' => $toStatus, + 'reopened_by' => $userId, + 'reopened_at' => $now, 'reopen_reason' => $reason, - 'updated_at' => $now, + 'updated_at' => $now, ]) >= 0; } } diff --git a/app/Models/AttendanceEmailTemplate.php b/app/Models/AttendanceEmailTemplate.php index 43b4f0a4..99496cb7 100644 --- a/app/Models/AttendanceEmailTemplate.php +++ b/app/Models/AttendanceEmailTemplate.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class AttendanceEmailTemplate extends BaseModel { protected $table = 'email_templates'; @@ -20,7 +22,7 @@ class AttendanceEmailTemplate extends BaseModel ]; protected $casts = [ - 'is_active' => 'boolean', + 'is_active' => 'boolean', 'updated_by' => 'integer', ]; diff --git a/app/Models/AttendanceRecord.php b/app/Models/AttendanceRecord.php index 2f3a46d4..79756eec 100644 --- a/app/Models/AttendanceRecord.php +++ b/app/Models/AttendanceRecord.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; class AttendanceRecord extends BaseModel @@ -27,14 +28,14 @@ class AttendanceRecord extends BaseModel ]; protected $casts = [ - 'class_section_id' => 'integer', - 'student_id' => 'integer', - 'school_id' => 'integer', - 'total_absence' => 'integer', - 'total_late' => 'integer', - 'total_presence' => 'integer', - 'total_attendance' => 'integer', - 'modified_by' => 'integer', + 'class_section_id' => 'integer', + 'student_id' => 'integer', + 'school_id' => 'integer', + 'total_absence' => 'integer', + 'total_late' => 'integer', + 'total_presence' => 'integer', + 'total_attendance' => 'integer', + 'modified_by' => 'integer', ]; /* ========================= @@ -85,7 +86,6 @@ class AttendanceRecord extends BaseModel public static function updateAttendanceRecord(int $attendanceId, array $data): bool { $affected = static::query()->whereKey($attendanceId)->update($data); - return $affected >= 0; } @@ -101,26 +101,20 @@ class AttendanceRecord extends BaseModel string $schoolYear, array $increments ): bool { - $allowed = ['total_absence', 'total_late', 'total_presence', 'total_attendance']; + $allowed = ['total_absence','total_late','total_presence','total_attendance']; $inc = array_intersect_key($increments, array_flip($allowed)); - if (empty($inc)) { - return true; - } + if (empty($inc)) return true; // Build atomic update: field = field + X $update = []; foreach ($inc as $field => $value) { $value = (int) $value; - if ($value === 0) { - continue; - } + if ($value === 0) continue; $update[$field] = DB::raw("COALESCE($field,0) + {$value}"); } - if (empty($update)) { - return true; - } + if (empty($update)) return true; $affected = static::query() ->where('student_id', $studentId) @@ -145,4 +139,4 @@ class AttendanceRecord extends BaseModel ->where('school_year', $schoolYear) ->sum('total_absence'); } -} +} \ No newline at end of file diff --git a/app/Models/AttendanceTracking.php b/app/Models/AttendanceTracking.php index 496a680a..c7148bd9 100644 --- a/app/Models/AttendanceTracking.php +++ b/app/Models/AttendanceTracking.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; @@ -25,11 +26,11 @@ class AttendanceTracking extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', - 'date' => 'datetime', // legacy dateFormat = datetime - 'is_reported' => 'integer', - 'is_notified' => 'integer', - 'notif_counter' => 'integer', + 'student_id' => 'integer', + 'date' => 'datetime', // legacy dateFormat = datetime + 'is_reported' => 'integer', + 'is_notified' => 'integer', + 'notif_counter' => 'integer', ]; /* ----------------------- Helpers ----------------------- */ @@ -41,7 +42,7 @@ class AttendanceTracking extends BaseModel return $date; } if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) { - return $date.' 00:00:00'; + return $date . ' 00:00:00'; } try { @@ -60,7 +61,6 @@ class AttendanceTracking extends BaseModel if ($schoolYear !== null && $schoolYear !== '') { $q->where('school_year', $schoolYear); } - return $q; } @@ -77,8 +77,8 @@ class AttendanceTracking extends BaseModel $y = (int) $d->format('Y'); $semester = ($m >= 8 && $m <= 12) ? 'Fall' : 'Spring'; - $startY = ($m >= 8) ? $y : $y - 1; - $endY = $startY + 1; + $startY = ($m >= 8) ? $y : $y - 1; + $endY = $startY + 1; return [$semester, sprintf('%d-%d', $startY, $endY)]; } @@ -89,7 +89,6 @@ class AttendanceTracking extends BaseModel $day = substr($ymd, 0, 10); $start = Carbon::parse($day, 'UTC')->startOfDay(); $endEx = Carbon::parse($day, 'UTC')->addDay()->startOfDay(); // exclusive - return [$start, $endEx]; } @@ -112,19 +111,19 @@ class AttendanceTracking extends BaseModel if ($semester === null || $schoolYear === null) { [$sem, $yr] = static::deriveTermFromDate($dt); - $semester = $semester ?? $sem; + $semester = $semester ?? $sem; $schoolYear = $schoolYear ?? $yr; } $row = static::create([ - 'student_id' => $studentId, - 'date' => $dt, - 'is_reported' => $isExcused ? 1 : 0, - 'reason' => $reason, - 'is_notified' => 0, - 'notif_counter' => 0, - 'semester' => $semester, - 'school_year' => $schoolYear, + 'student_id' => $studentId, + 'date' => $dt, + 'is_reported' => $isExcused ? 1 : 0, + 'reason' => $reason, + 'is_notified' => 0, + 'notif_counter' => 0, + 'semester' => $semester, + 'school_year' => $schoolYear, ]); return (int) $row->id; @@ -145,7 +144,7 @@ class AttendanceTracking extends BaseModel if ($startDate) { if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $startDate)) { - [$start] = static::dayRange($startDate); + [$start, ] = static::dayRange($startDate); $q->where('date', '>=', $start); } else { $q->where('date', '>=', static::normalizeDateTime($startDate)); @@ -202,7 +201,7 @@ class AttendanceTracking extends BaseModel ?string $schoolYear = null ): bool { $startDay = Carbon::now('UTC')->subDays($days)->toDateString(); - [$start] = static::dayRange($startDay); + [$start, ] = static::dayRange($startDay); $q = static::query() ->where('student_id', $studentId) @@ -232,17 +231,13 @@ class AttendanceTracking extends BaseModel $absences = $q->orderByDesc('date')->limit($threshold)->get()->toArray(); - if (count($absences) < $threshold) { - return false; - } + if (count($absences) < $threshold) return false; for ($i = 0; $i < $threshold - 1; $i++) { $d1 = new \DateTime($absences[$i]['date']); $d2 = new \DateTime($absences[$i + 1]['date']); $diffDays = (int) $d2->diff($d1)->format('%a'); - if ($diffDays !== 7) { - return false; - } + if ($diffDays !== 7) return false; } return true; @@ -269,13 +264,11 @@ class AttendanceTracking extends BaseModel $records = $q->orderByDesc('date')->limit($weeksStreak)->get()->toArray(); - if (count($records) < $weeksStreak) { - return false; - } + if (count($records) < $weeksStreak) return false; $count = 0; foreach ($records as $r) { - if ((int) ($r['is_reported'] ?? 0) === 0 && (int) ($r['is_notified'] ?? 0) === 0) { + if ((int)($r['is_reported'] ?? 0) === 0 && (int)($r['is_notified'] ?? 0) === 0) { $count++; } } @@ -304,9 +297,9 @@ class AttendanceTracking extends BaseModel $last = $q3->orderByDesc('date')->first(); return [ - 'total_absences' => $total, + 'total_absences' => $total, 'unexcused_absences' => $unexcused, - 'last_absence' => $last ? $last->toArray() : null, + 'last_absence' => $last ? $last->toArray() : null, ]; } @@ -320,10 +313,7 @@ class AttendanceTracking extends BaseModel ) { $q = static::query(); static::applyTermFilters($q, $semester, $schoolYear); - if ($limit > 0) { - $q->limit($limit); - } - + if ($limit > 0) $q->limit($limit); return $q->orderByDesc('date')->get(); } @@ -345,8 +335,8 @@ class AttendanceTracking extends BaseModel $students = (int) $q3->distinct('student_id')->count('student_id'); return [ - 'total_absences' => $total, - 'unexcused_absences' => $unexcused, + 'total_absences' => $total, + 'unexcused_absences' => $unexcused, 'students_with_absences' => $students, ]; } @@ -362,28 +352,26 @@ class AttendanceTracking extends BaseModel foreach ($studentsWithViolations as $student) { if (empty($student['absences'])) { $results['skipped']++; - continue; } foreach ($student['absences'] as $absence) { - $ymd = substr((string) ($absence['date'] ?? now()->toDateString()), 0, 10); + $ymd = substr((string)($absence['date'] ?? now()->toDateString()), 0, 10); [$start, $endEx] = static::dayRange($ymd); $data = [ - 'student_id' => (int) ($student['id'] ?? 0), - 'date' => static::normalizeDateTime($ymd), - 'is_reported' => 0, - 'reason' => (string) ($student['violation'] ?? ''), - 'is_notified' => 0, - 'notif_counter' => 0, - 'semester' => $semester, - 'school_year' => $schoolYear, + 'student_id' => (int)($student['id'] ?? 0), + 'date' => static::normalizeDateTime($ymd), + 'is_reported' => 0, + 'reason' => (string)($student['violation'] ?? ''), + 'is_notified' => 0, + 'notif_counter' => 0, + 'semester' => $semester, + 'school_year' => $schoolYear, ]; if ($data['student_id'] <= 0) { $results['skipped']++; - continue; } @@ -403,8 +391,8 @@ class AttendanceTracking extends BaseModel $existing->fill($data)->save(); $results['updated']++; - if (! empty($existing->is_notified)) { - static::resetNotification((int) $existing->id); + if (!empty($existing->is_notified)) { + static::resetNotification((int)$existing->id); $results['notified']++; } } else { @@ -416,7 +404,7 @@ class AttendanceTracking extends BaseModel // Only match standalone "4" if (preg_match('/\b4\b/', $data['reason'])) { - static::markAsNotified((int) $new->id); + static::markAsNotified((int)$new->id); $results['notified']++; } } @@ -439,8 +427,8 @@ class AttendanceTracking extends BaseModel ->whereKey($id) ->update([ 'notif_counter' => DB::raw('COALESCE(notif_counter,0)+1'), - 'is_notified' => 1, - 'updated_at' => now(), + 'is_notified' => 1, + 'updated_at' => now(), ]); return $affected > 0; @@ -451,9 +439,9 @@ class AttendanceTracking extends BaseModel $affected = static::query() ->whereKey($id) ->update([ - 'is_notified' => 0, + 'is_notified' => 0, 'notif_counter' => 0, - 'updated_at' => now(), + 'updated_at' => now(), ]); return $affected >= 0; @@ -475,7 +463,7 @@ class AttendanceTracking extends BaseModel // Here we require term to be passed or derived from date. if ($semester === null || $schoolYear === null) { [$sem, $yr] = static::deriveTermFromDate($ymd); - $semester = $semester ?? $sem; + $semester = $semester ?? $sem; $schoolYear = $schoolYear ?? $yr; } @@ -487,33 +475,33 @@ class AttendanceTracking extends BaseModel ->where('semester', $semester) ->where('school_year', $schoolYear) ->where('date', '>=', $start) - ->where('date', '<', $endEx) + ->where('date', '<', $endEx) ->where('reason', 'like', "%{$code}%") ->orderByDesc('date') ->first(); // 2) Fallback: match by day only - if (! $row) { + if (!$row) { $row = static::query() ->where('student_id', $studentId) ->where('semester', $semester) ->where('school_year', $schoolYear) ->where('date', '>=', $start) - ->where('date', '<', $endEx) + ->where('date', '<', $endEx) ->orderByDesc('date') ->first(); } if ($row) { - $counter = ((int) ($row->notif_counter ?? 0)) + 1; + $counter = ((int)($row->notif_counter ?? 0)) + 1; $affected = static::query() - ->whereKey((int) $row->id) + ->whereKey((int)$row->id) ->update([ - 'is_notified' => 1, + 'is_notified' => 1, 'notif_counter' => $counter, - 'is_reported' => 0, - 'updated_at' => now(), + 'is_reported' => 0, + 'updated_at' => now(), ]); return $affected > 0; @@ -521,18 +509,18 @@ class AttendanceTracking extends BaseModel // Insert a row so future runs see it as notified $created = static::create([ - 'student_id' => $studentId, - 'date' => static::normalizeDateTime($ymd), - 'is_reported' => 0, - 'reason' => $code, - 'is_notified' => 1, - 'notif_counter' => 1, - 'semester' => $semester, - 'school_year' => $schoolYear, - 'note' => null, + 'student_id' => $studentId, + 'date' => static::normalizeDateTime($ymd), + 'is_reported' => 0, + 'reason' => $code, + 'is_notified' => 1, + 'notif_counter' => 1, + 'semester' => $semester, + 'school_year' => $schoolYear, + 'note' => null, ]); - return ! empty($created->id); + return !empty($created->id); } /** @@ -550,11 +538,11 @@ class AttendanceTracking extends BaseModel ->where('student_id', $studentId) ->where('school_year', $schoolYear); - if (! empty($semester)) { + if (!empty($semester)) { $q->where('semester', $semester); } - if (! empty($lastDate)) { + if (!empty($lastDate)) { $q->where('date', '<=', static::normalizeDateTime($lastDate)); } @@ -562,20 +550,18 @@ class AttendanceTracking extends BaseModel ->orderByDesc('date') ->first(); - if (! $row) { - return 0; - } + if (!$row) return 0; - $counter = ((int) ($row->notif_counter ?? 0)) + 1; + $counter = ((int)($row->notif_counter ?? 0)) + 1; $affected = static::query() - ->whereKey((int) $row->id) + ->whereKey((int)$row->id) ->update([ - 'is_notified' => 1, + 'is_notified' => 1, 'notif_counter' => $counter, - 'updated_at' => now(), + 'updated_at' => now(), ]); return $affected > 0 ? 1 : 0; } -} +} \ No newline at end of file diff --git a/app/Models/AuthorizedUser.php b/app/Models/AuthorizedUser.php index 3f9333c8..d51ddb81 100644 --- a/app/Models/AuthorizedUser.php +++ b/app/Models/AuthorizedUser.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class AuthorizedUser extends BaseModel { protected $table = 'authorized_users'; @@ -25,7 +27,7 @@ class AuthorizedUser extends BaseModel ]; protected $casts = [ - 'user_id' => 'integer', + 'user_id' => 'integer', 'authorized_user_id' => 'integer', ]; @@ -42,4 +44,4 @@ class AuthorizedUser extends BaseModel { return $this->belongsTo(User::class, 'authorized_user_id'); } -} +} \ No newline at end of file diff --git a/app/Models/BadgePrintLog.php b/app/Models/BadgePrintLog.php index 88a5206a..af7d3fcd 100644 --- a/app/Models/BadgePrintLog.php +++ b/app/Models/BadgePrintLog.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\QueryException; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; @@ -24,19 +25,21 @@ class BadgePrintLog extends BaseModel ]; protected $casts = [ - 'user_id' => 'integer', - 'printed_by' => 'integer', - 'printed_at' => 'datetime', - 'copies' => 'integer', + 'user_id' => 'integer', + 'printed_by' => 'integer', + 'printed_at' => 'datetime', + 'copies' => 'integer', ]; /** * Insert a batch of print logs. Swallows errors if table is missing. * - * @param int[] $userIds - * @param array $roleMap userId => role label - * @param array $classMap userId => class name - * @param int $copies copies per user (defaults to 1) + * @param int[] $userIds + * @param int|null $printedBy + * @param string|null $schoolYear + * @param array $roleMap userId => role label + * @param array $classMap userId => class name + * @param int $copies copies per user (defaults to 1) * @return int rows inserted (best-effort) */ public static function logPrints( @@ -52,38 +55,31 @@ class BadgePrintLog extends BaseModel foreach ($userIds as $uid) { $uid = (int) $uid; - if ($uid <= 0) { - continue; - } + if ($uid <= 0) continue; $rows[] = [ - 'user_id' => $uid, - 'printed_by' => $printedBy, - 'school_year' => $schoolYear, - 'printed_at' => $now, - 'role' => (string) ($roleMap[$uid] ?? ''), - 'class_section_name' => (string) ($classMap[$uid] ?? ''), - 'copies' => max(1, (int) $copies), + 'user_id' => $uid, + 'printed_by' => $printedBy, + 'school_year' => $schoolYear, + 'printed_at' => $now, + 'role' => (string)($roleMap[$uid] ?? ''), + 'class_section_name' => (string)($classMap[$uid] ?? ''), + 'copies' => max(1, (int) $copies), ]; } - if (empty($rows)) { - return 0; - } + if (empty($rows)) return 0; try { // insert returns bool; we return count best-effort like legacy DB::table((new static)->getTable())->insert($rows); - return count($rows); } catch (QueryException $e) { // Avoid breaking badge/PDF generation if the table is missing or other DB error - Log::error('BadgePrintLog::logPrints failed: '.$e->getMessage()); - + Log::error('BadgePrintLog::logPrints failed: ' . $e->getMessage()); return 0; } catch (\Throwable $e) { - Log::error('BadgePrintLog::logPrints failed: '.$e->getMessage()); - + Log::error('BadgePrintLog::logPrints failed: ' . $e->getMessage()); return 0; } } @@ -91,35 +87,31 @@ class BadgePrintLog extends BaseModel /** * Return counts and last printed info for given user IDs. * - * @param int[] $userIds - * @param string|null $schoolYear Optional filter by school year + * @param int[] $userIds + * @param string|null $schoolYear Optional filter by school year * @return array userId => [count, last_printed_at, last_printed_by] */ public static function getStatus(array $userIds, ?string $schoolYear = null): array { $userIds = array_values(array_unique(array_map('intval', array_filter($userIds)))); - if (empty($userIds)) { - return []; - } + if (empty($userIds)) return []; try { - $q = DB::table((new static)->getTable().' as l') + $q = DB::table((new static)->getTable() . ' as l') ->selectRaw('l.user_id, COUNT(*) AS prints, MAX(l.printed_at) AS last_printed_at, MAX(l.printed_by) AS last_printed_by') ->whereIn('l.user_id', $userIds) ->groupBy('l.user_id'); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('l.school_year', $schoolYear); } $rows = $q->get(); } catch (QueryException $e) { - Log::error('BadgePrintLog::getStatus failed: '.$e->getMessage()); - + Log::error('BadgePrintLog::getStatus failed: ' . $e->getMessage()); return []; } catch (\Throwable $e) { - Log::error('BadgePrintLog::getStatus failed: '.$e->getMessage()); - + Log::error('BadgePrintLog::getStatus failed: ' . $e->getMessage()); return []; } @@ -127,7 +119,7 @@ class BadgePrintLog extends BaseModel foreach ($rows as $r) { $uid = (int) ($r->user_id ?? 0); $out[$uid] = [ - 'count' => (int) ($r->prints ?? 0), + 'count' => (int) ($r->prints ?? 0), 'last_printed_at' => (string) ($r->last_printed_at ?? ''), 'last_printed_by' => isset($r->last_printed_by) ? (int) $r->last_printed_by : null, ]; @@ -146,4 +138,4 @@ class BadgePrintLog extends BaseModel { return $this->belongsTo(User::class, 'printed_by'); } -} +} \ No newline at end of file diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php index bcdf9fa0..6d35fb69 100644 --- a/app/Models/BaseModel.php +++ b/app/Models/BaseModel.php @@ -3,7 +3,6 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; -use Illuminate\Foundation\Application; class BaseModel extends Model { @@ -13,9 +12,8 @@ class BaseModel extends Model { if ($this->isTestingEnv()) { $columns = $this->tableColumns(); - if (! empty($columns)) { + if (!empty($columns)) { $key = $this->getKeyName(); - return array_values(array_filter($columns, static function ($col) use ($key) { return $col !== $key; })); @@ -24,10 +22,10 @@ class BaseModel extends Model $fillable = parent::getFillable(); if ($this->timestamps) { - if (! in_array('created_at', $fillable, true)) { + if (!in_array('created_at', $fillable, true)) { $fillable[] = 'created_at'; } - if (! in_array('updated_at', $fillable, true)) { + if (!in_array('updated_at', $fillable, true)) { $fillable[] = 'updated_at'; } } @@ -51,7 +49,7 @@ class BaseModel extends Model if (function_exists('app')) { try { $app = app(); - if ($app instanceof Application && $app->runningUnitTests()) { + if ($app instanceof \Illuminate\Foundation\Application && $app->runningUnitTests()) { return true; } } catch (\Throwable $e) { @@ -84,7 +82,7 @@ class BaseModel extends Model } if ($pattern === null) { - $pattern = __DIR__.'/../../database/migrations/*.php'; + $pattern = __DIR__ . '/../../database/migrations/*.php'; } $files = glob($pattern) ?: []; @@ -100,7 +98,7 @@ class BaseModel extends Model } foreach ($this->parseSchemaCreateTables($contents) as $table => $columns) { - if (! isset($map[$table]) || empty($map[$table])) { + if (!isset($map[$table]) || empty($map[$table])) { $map[$table] = $columns; } } @@ -118,7 +116,7 @@ class BaseModel extends Model $colsBlock = $match[2]; preg_match_all('/`([^`]+)`\\s+[^,]+/m', $colsBlock, $colsMatch); $columns = $colsMatch[1] ?? []; - if (! empty($columns)) { + if (!empty($columns)) { $map[$table] = $columns; } } @@ -130,7 +128,7 @@ class BaseModel extends Model private function parseSchemaCreateTables(string $contents): array { $map = []; - if (! preg_match_all('/Schema::create\\(\\s*[\'"]([^\'"]+)[\'"]\\s*,\\s*function\\s*\\([^)]*\\)\\s*\\{(.*?)\\n\\s*\\}\\);/is', $contents, $matches, PREG_SET_ORDER)) { + if (!preg_match_all('/Schema::create\\(\\s*[\'"]([^\'"]+)[\'"]\\s*,\\s*function\\s*\\([^)]*\\)\\s*\\{(.*?)\\n\\s*\\}\\);/is', $contents, $matches, PREG_SET_ORDER)) { return $map; } @@ -152,7 +150,7 @@ class BaseModel extends Model $columns[] = 'deleted_at'; } - if (! empty($columns)) { + if (!empty($columns)) { $map[$table] = $columns; } } diff --git a/app/Models/Calendar.php b/app/Models/Calendar.php index a1dfd891..e1692f17 100644 --- a/app/Models/Calendar.php +++ b/app/Models/Calendar.php @@ -2,4 +2,6 @@ namespace App\Models; -class Calendar extends CalendarEvent {} +class Calendar extends CalendarEvent +{ +} diff --git a/app/Models/CalendarEvent.php b/app/Models/CalendarEvent.php index bab56d26..bcb814bf 100644 --- a/app/Models/CalendarEvent.php +++ b/app/Models/CalendarEvent.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; @@ -30,12 +31,12 @@ class CalendarEvent extends BaseModel protected $casts = [ // If your column is DATE use 'date', if it's DATETIME use 'datetime' - 'date' => 'date', - 'notify_parent' => 'boolean', - 'notify_admin' => 'boolean', + 'date' => 'date', + 'notify_parent' => 'boolean', + 'notify_admin' => 'boolean', 'notify_teacher' => 'boolean', - 'no_school' => 'integer', - 'event_type' => 'string', + 'no_school' => 'integer', + 'event_type' => 'string', ]; private static ?bool $hasEventTypeColumn = null; @@ -47,21 +48,18 @@ class CalendarEvent extends BaseModel public static function getEvents() { $events = static::query()->get()->toArray(); - return static::withNoSchoolFlag($events); } public static function getEventByDate(string $date): array { $events = static::query()->where('date', $date)->get()->toArray(); - return static::withNoSchoolFlag($events); } public static function addEvent(array $data): int { $row = static::create($data); - return (int) $row->id; } @@ -94,7 +92,6 @@ class CalendarEvent extends BaseModel if (static::$hasEventTypeColumn === null) { static::$hasEventTypeColumn = static::columnExists((new static)->getTable(), 'event_type'); } - return (bool) static::$hasEventTypeColumn; } @@ -126,9 +123,9 @@ class CalendarEvent extends BaseModel */ protected static function isNoSchoolEvent(array $event): bool { - $title = strtolower((string) ($event['title'] ?? '')); - $desc = strtolower((string) ($event['description'] ?? '')); - $text = $title.' '.$desc; + $title = strtolower((string)($event['title'] ?? '')); + $desc = strtolower((string)($event['description'] ?? '')); + $text = $title . ' ' . $desc; $keywords = ['no school', 'no-school', 'cancel', 'vacation', 'holiday', 'break']; diff --git a/app/Models/ClassModel.php b/app/Models/ClassModel.php index b63baabc..2c2d287f 100644 --- a/app/Models/ClassModel.php +++ b/app/Models/ClassModel.php @@ -2,4 +2,6 @@ namespace App\Models; -class ClassModel extends SchoolClass {} +class ClassModel extends SchoolClass +{ +} diff --git a/app/Models/ClassPrepAdjustment.php b/app/Models/ClassPrepAdjustment.php index cc353221..5fafae83 100644 --- a/app/Models/ClassPrepAdjustment.php +++ b/app/Models/ClassPrepAdjustment.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class ClassPrepAdjustment extends BaseModel { protected $table = 'class_prep_adjustments'; @@ -19,7 +21,7 @@ class ClassPrepAdjustment extends BaseModel protected $casts = [ 'class_section_id' => 'integer', - 'adjustment' => 'integer', // change to 'decimal:2' if it's not an int + 'adjustment' => 'integer', // change to 'decimal:2' if it's not an int ]; // Optional relationship @@ -27,4 +29,4 @@ class ClassPrepAdjustment extends BaseModel { return $this->belongsTo(ClassSection::class, 'class_section_id'); } -} +} \ No newline at end of file diff --git a/app/Models/ClassPreparationLog.php b/app/Models/ClassPreparationLog.php index 11891993..2601b91b 100644 --- a/app/Models/ClassPreparationLog.php +++ b/app/Models/ClassPreparationLog.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class ClassPreparationLog extends BaseModel { protected $table = 'class_preparation_log'; @@ -20,7 +22,7 @@ class ClassPreparationLog extends BaseModel protected $casts = [ 'class_section_id' => 'integer', // If prep_data is JSON in DB, use 'array' (or 'json') cast: - 'prep_data' => 'array', + 'prep_data' => 'array', ]; // Optional relationship @@ -28,4 +30,4 @@ class ClassPreparationLog extends BaseModel { return $this->belongsTo(ClassSection::class, 'class_section_id'); } -} +} \ No newline at end of file diff --git a/app/Models/ClassProgressAttachment.php b/app/Models/ClassProgressAttachment.php index bfd1ed8d..b0c77514 100644 --- a/app/Models/ClassProgressAttachment.php +++ b/app/Models/ClassProgressAttachment.php @@ -2,12 +2,12 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Factories\HasFactory; class ClassProgressAttachment extends BaseModel { use HasFactory; - protected $table = 'class_progress_attachments'; // legacy: useTimestamps = false @@ -23,8 +23,8 @@ class ClassProgressAttachment extends BaseModel ]; protected $casts = [ - 'report_id' => 'integer', - 'file_size' => 'integer', + 'report_id' => 'integer', + 'file_size' => 'integer', ]; // Optional relationship diff --git a/app/Models/ClassProgressReport.php b/app/Models/ClassProgressReport.php index 89e224b3..9badfcd8 100644 --- a/app/Models/ClassProgressReport.php +++ b/app/Models/ClassProgressReport.php @@ -2,12 +2,12 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Factories\HasFactory; class ClassProgressReport extends BaseModel { use HasFactory; - protected $table = 'class_progress_reports'; // ✅ legacy: useTimestamps = true (created_at/updated_at) @@ -36,14 +36,14 @@ class ClassProgressReport extends BaseModel protected $casts = [ 'class_section_id' => 'integer', - 'teacher_id' => 'integer', + 'teacher_id' => 'integer', // change to 'datetime' if your columns are DATETIME - 'week_start' => 'date', - 'week_end' => 'date', + 'week_start' => 'date', + 'week_end' => 'date', // If flags_json is JSON in DB, this makes it an array automatically - 'flags_json' => 'array', + 'flags_json' => 'array', ]; /* Optional relationships */ diff --git a/app/Models/ClassSection.php b/app/Models/ClassSection.php index 0c6477d5..0f517359 100644 --- a/app/Models/ClassSection.php +++ b/app/Models/ClassSection.php @@ -2,13 +2,13 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Support\Facades\DB; class ClassSection extends BaseModel { use HasFactory; - // legacy table name is "classSection" protected $table = 'classSection'; @@ -24,7 +24,7 @@ class ClassSection extends BaseModel ]; protected $casts = [ - 'class_id' => 'integer', + 'class_id' => 'integer', 'class_section_id' => 'integer', ]; diff --git a/app/Models/Communication.php b/app/Models/Communication.php index 8703135a..abdcab5a 100644 --- a/app/Models/Communication.php +++ b/app/Models/Communication.php @@ -2,4 +2,6 @@ namespace App\Models; -class Communication extends CommunicationLog {} +class Communication extends CommunicationLog +{ +} diff --git a/app/Models/CommunicationLog.php b/app/Models/CommunicationLog.php index db0c87c6..6b4cb08a 100644 --- a/app/Models/CommunicationLog.php +++ b/app/Models/CommunicationLog.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class CommunicationLog extends BaseModel { protected $table = 'communication_logs'; @@ -32,16 +34,16 @@ class CommunicationLog extends BaseModel } protected $casts = [ - 'student_id' => 'integer', - 'family_id' => 'integer', - 'sent_by' => 'integer', + 'student_id' => 'integer', + 'family_id' => 'integer', + 'sent_by' => 'integer', // If these columns are JSON in DB, this will auto convert to arrays - 'recipients' => 'array', - 'cc' => 'array', - 'bcc' => 'array', - 'attachments' => 'array', - 'metadata' => 'array', + 'recipients' => 'array', + 'cc' => 'array', + 'bcc' => 'array', + 'attachments' => 'array', + 'metadata' => 'array', ]; /* Optional relationships */ diff --git a/app/Models/Competition.php b/app/Models/Competition.php index 660a682b..40430f46 100644 --- a/app/Models/Competition.php +++ b/app/Models/Competition.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\SoftDeletes; class Competition extends BaseModel @@ -33,20 +34,20 @@ class Competition extends BaseModel protected $casts = [ 'class_section_id' => 'integer', - 'winners_count' => 'integer', - 'prize_per_point' => 'decimal:2', // adjust precision if needed + 'winners_count' => 'integer', + 'prize_per_point' => 'decimal:2', // adjust precision if needed - 'is_published' => 'boolean', - 'is_locked' => 'boolean', + 'is_published' => 'boolean', + 'is_locked' => 'boolean', // change to 'date' if your columns are DATE (not DATETIME) - 'start_date' => 'date', - 'end_date' => 'date', - 'published_at' => 'datetime', - 'locked_at' => 'datetime', + 'start_date' => 'date', + 'end_date' => 'date', + 'published_at' => 'datetime', + 'locked_at' => 'datetime', - 'locked_by' => 'integer', - 'created_by' => 'integer', + 'locked_by' => 'integer', + 'created_by' => 'integer', ]; /* Optional relationships */ @@ -69,4 +70,4 @@ class Competition extends BaseModel { return $this->hasMany(CompetitionClassWinner::class, 'competition_id'); } -} +} \ No newline at end of file diff --git a/app/Models/CompetitionClassWinner.php b/app/Models/CompetitionClassWinner.php index a718a992..3d3c5ef4 100644 --- a/app/Models/CompetitionClassWinner.php +++ b/app/Models/CompetitionClassWinner.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class CompetitionClassWinner extends BaseModel { protected $table = 'competition_class_winners'; @@ -23,10 +25,10 @@ class CompetitionClassWinner extends BaseModel ]; protected $casts = [ - 'competition_id' => 'integer', - 'class_section_id' => 'integer', - 'question_count' => 'integer', - 'winners_override' => 'integer', + 'competition_id' => 'integer', + 'class_section_id' => 'integer', + 'question_count' => 'integer', + 'winners_override' => 'integer', ]; /* Optional relationships */ @@ -39,4 +41,4 @@ class CompetitionClassWinner extends BaseModel { return $this->belongsTo(ClassSection::class, 'class_section_id'); } -} +} \ No newline at end of file diff --git a/app/Models/CompetitionScore.php b/app/Models/CompetitionScore.php index d4a49133..0d745cd0 100644 --- a/app/Models/CompetitionScore.php +++ b/app/Models/CompetitionScore.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class CompetitionScore extends BaseModel { protected $table = 'competition_scores'; @@ -18,10 +20,10 @@ class CompetitionScore extends BaseModel ]; protected $casts = [ - 'competition_id' => 'integer', - 'student_id' => 'integer', + 'competition_id' => 'integer', + 'student_id' => 'integer', 'class_section_id' => 'integer', - 'score' => 'integer', // change to 'decimal:2' if score is not int + 'score' => 'integer', // change to 'decimal:2' if score is not int ]; /* Optional relationships */ @@ -39,4 +41,4 @@ class CompetitionScore extends BaseModel { return $this->belongsTo(ClassSection::class, 'class_section_id'); } -} +} \ No newline at end of file diff --git a/app/Models/CompetitionWinner.php b/app/Models/CompetitionWinner.php index c9b47616..84c1126d 100644 --- a/app/Models/CompetitionWinner.php +++ b/app/Models/CompetitionWinner.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class CompetitionWinner extends BaseModel { protected $table = 'competition_winners'; @@ -20,13 +22,13 @@ class CompetitionWinner extends BaseModel ]; protected $casts = [ - 'competition_id' => 'integer', - 'student_id' => 'integer', + 'competition_id' => 'integer', + 'student_id' => 'integer', 'class_section_id' => 'integer', - 'rank' => 'integer', - 'score' => 'integer', // change to 'decimal:2' if needed - 'prize_amount' => 'decimal:2', // adjust precision if needed - 'created_at' => 'datetime', + 'rank' => 'integer', + 'score' => 'integer', // change to 'decimal:2' if needed + 'prize_amount' => 'decimal:2', // adjust precision if needed + 'created_at' => 'datetime', ]; /* Optional relationships */ @@ -44,4 +46,4 @@ class CompetitionWinner extends BaseModel { return $this->belongsTo(ClassSection::class, 'class_section_id'); } -} +} \ No newline at end of file diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index f5c433ef..c8cc91ab 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -2,7 +2,8 @@ namespace App\Models; -use App\Services\SemesterRangeService; +use App\Models\BaseModel; +use Illuminate\Support\Facades\DB; class Configuration extends BaseModel { @@ -57,11 +58,11 @@ class Configuration extends BaseModel } $row = static::query()->create([ - 'config_key' => $key, + 'config_key' => $key, 'config_value' => $value, ]); - return ! empty($row->id); + return !empty($row->id); } /** @@ -86,7 +87,6 @@ class Configuration extends BaseModel public static function addConfig(array $data): int { $row = static::query()->create($data); - return (int) $row->id; } @@ -104,7 +104,7 @@ class Configuration extends BaseModel try { // If you have this service in Laravel, inject/resolve it from container. // This call assumes the service constructor can accept Configuration model (like legacy did). - $semester = app(SemesterRangeService::class)->getSemesterForDate(); + $semester = app(\App\Services\SemesterRangeService::class)->getSemesterForDate(); if (is_string($semester) && $semester !== '') { return $semester; } diff --git a/app/Models/ContactUs.php b/app/Models/ContactUs.php index 0bfd8c0f..e891a22f 100644 --- a/app/Models/ContactUs.php +++ b/app/Models/ContactUs.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class ContactUs extends BaseModel { protected $table = 'contactus'; @@ -21,7 +23,7 @@ class ContactUs extends BaseModel ]; protected $casts = [ - 'sender_id' => 'integer', + 'sender_id' => 'integer', 'reciever_id' => 'integer', ]; @@ -77,4 +79,4 @@ class ContactUs extends BaseModel { return static::query()->whereKey($id)->update($data) >= 0; } -} +} \ No newline at end of file diff --git a/app/Models/CurrentFlag.php b/app/Models/CurrentFlag.php index 7e9cf71d..1382c2df 100644 --- a/app/Models/CurrentFlag.php +++ b/app/Models/CurrentFlag.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class CurrentFlag extends BaseModel { protected $table = 'current_flag'; @@ -31,11 +33,11 @@ class CurrentFlag extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', - 'updated_by_open' => 'integer', - 'updated_by_closed' => 'integer', - 'updated_by_canceled' => 'integer', - 'flag_datetime' => 'datetime', + 'student_id' => 'integer', + 'updated_by_open' => 'integer', + 'updated_by_closed' => 'integer', + 'updated_by_canceled'=> 'integer', + 'flag_datetime' => 'datetime', ]; /* Optional relationships */ @@ -58,4 +60,4 @@ class CurrentFlag extends BaseModel { return $this->belongsTo(User::class, 'updated_by_canceled'); } -} +} \ No newline at end of file diff --git a/app/Models/CurrentIncident.php b/app/Models/CurrentIncident.php index b106466a..4cf08894 100644 --- a/app/Models/CurrentIncident.php +++ b/app/Models/CurrentIncident.php @@ -2,10 +2,11 @@ namespace App\Models; +use App\Models\BaseModel; + class CurrentIncident extends BaseModel { protected $table = 'current_incident'; - public $timestamps = true; protected $fillable = [ diff --git a/app/Models/DiscountUsage.php b/app/Models/DiscountUsage.php index b7620201..fc780085 100644 --- a/app/Models/DiscountUsage.php +++ b/app/Models/DiscountUsage.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; class DiscountUsage extends BaseModel @@ -23,12 +24,12 @@ class DiscountUsage extends BaseModel ]; protected $casts = [ - 'voucher_id' => 'integer', - 'invoice_id' => 'integer', - 'discount_amount' => 'decimal:2', // adjust precision if needed - 'updated_by' => 'integer', - 'parent_id' => 'integer', - 'used_at' => 'datetime', + 'voucher_id' => 'integer', + 'invoice_id' => 'integer', + 'discount_amount' => 'decimal:2', // adjust precision if needed + 'updated_by' => 'integer', + 'parent_id' => 'integer', + 'used_at' => 'datetime', ]; /* Optional relationships */ @@ -55,4 +56,4 @@ class DiscountUsage extends BaseModel return (float) $total; } -} +} \ No newline at end of file diff --git a/app/Models/DiscountVoucher.php b/app/Models/DiscountVoucher.php index 6defb93f..21a99b29 100644 --- a/app/Models/DiscountVoucher.php +++ b/app/Models/DiscountVoucher.php @@ -2,7 +2,9 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\DB; class DiscountVoucher extends BaseModel { @@ -29,11 +31,11 @@ class DiscountVoucher extends BaseModel protected $casts = [ 'discount_value' => 'decimal:2', - 'max_uses' => 'integer', - 'times_used' => 'integer', - 'is_active' => 'boolean', - 'valid_from' => 'date', - 'valid_until' => 'date', + 'max_uses' => 'integer', + 'times_used' => 'integer', + 'is_active' => 'boolean', + 'valid_from' => 'date', + 'valid_until' => 'date', ]; /* ========================= @@ -88,8 +90,8 @@ class DiscountVoucher extends BaseModel private function validateDatesOrder(): void { - if (! empty($this->valid_from) && ! empty($this->valid_until)) { - $from = Carbon::parse($this->valid_from)->toDateString(); + if (!empty($this->valid_from) && !empty($this->valid_until)) { + $from = Carbon::parse($this->valid_from)->toDateString(); $until = Carbon::parse($this->valid_until)->toDateString(); if ($from > $until) { // In Laravel, prefer validating in FormRequest. @@ -121,24 +123,24 @@ class DiscountVoucher extends BaseModel // Left join usages for this student only ->leftJoin('discount_usages as u', function ($join) use ($studentId) { $join->on('u.voucher_id', '=', 'v.id') - ->where('u.student_id', '=', (int) $studentId); + ->where('u.student_id', '=', (int) $studentId); }) ->where('v.code', $code) ->where('v.is_active', 1) // valid_from is null or <= today ->where(function ($w) use ($today) { $w->whereNull('v.valid_from') - ->orWhere('v.valid_from', '<=', $today); + ->orWhere('v.valid_from', '<=', $today); }) // valid_until is null or >= today ->where(function ($w) use ($today) { $w->whereNull('v.valid_until') - ->orWhere('v.valid_until', '>=', $today); + ->orWhere('v.valid_until', '>=', $today); }) // max_uses is null or times_used < max_uses ->where(function ($w) { $w->whereNull('v.max_uses') - ->orWhereColumn('v.times_used', '<', 'v.max_uses'); + ->orWhereColumn('v.times_used', '<', 'v.max_uses'); }) // Not previously used by this student (no usage row) ->whereNull('u.id') @@ -146,4 +148,4 @@ class DiscountVoucher extends BaseModel return $q->first(); } -} +} \ No newline at end of file diff --git a/app/Models/EarlyDismissalSignature.php b/app/Models/EarlyDismissalSignature.php index 63d0d7d5..f9a703c4 100644 --- a/app/Models/EarlyDismissalSignature.php +++ b/app/Models/EarlyDismissalSignature.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class EarlyDismissalSignature extends BaseModel { protected $table = 'early_dismissal_signatures'; @@ -24,7 +26,7 @@ class EarlyDismissalSignature extends BaseModel // report_date is stored as Y-m-d in legacy validation; keep as date 'report_date' => 'date', - 'file_size' => 'integer', + 'file_size' => 'integer', 'uploaded_by' => 'integer', ]; @@ -33,4 +35,4 @@ class EarlyDismissalSignature extends BaseModel { return $this->belongsTo(User::class, 'uploaded_by'); } -} +} \ No newline at end of file diff --git a/app/Models/EmailTemplate.php b/app/Models/EmailTemplate.php index b604b1b0..cf05bacf 100644 --- a/app/Models/EmailTemplate.php +++ b/app/Models/EmailTemplate.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class EmailTemplate extends BaseModel { protected $table = 'email_templates'; @@ -29,9 +31,9 @@ class EmailTemplate extends BaseModel ->where('is_active', 1) ->where(function ($q) use ($variant) { $q->where('variant', $variant) - ->orWhere('variant', 'default'); + ->orWhere('variant', 'default'); }) - ->orderByRaw('CASE WHEN variant = ? THEN 0 ELSE 1 END', [$variant]) + ->orderByRaw("CASE WHEN variant = ? THEN 0 ELSE 1 END", [$variant]) ->first(); return $row; diff --git a/app/Models/EmergencyContact.php b/app/Models/EmergencyContact.php index 555d1d53..23d898df 100644 --- a/app/Models/EmergencyContact.php +++ b/app/Models/EmergencyContact.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class EmergencyContact extends BaseModel { protected $table = 'emergency_contacts'; @@ -22,8 +24,8 @@ class EmergencyContact extends BaseModel ]; protected $casts = [ - 'parent_id' => 'integer', - 'student_id' => 'integer', + 'parent_id' => 'integer', + 'student_id' => 'integer', 'authorized_user_id' => 'integer', ]; @@ -70,7 +72,7 @@ class EmergencyContact extends BaseModel return static::query() ->where(function ($q) use ($studentId) { $q->where('student_id', $studentId) - ->orWhere('parent_id', $studentId); + ->orWhere('parent_id', $studentId); }) ->get(); } diff --git a/app/Models/Enrollment.php b/app/Models/Enrollment.php index 605c3731..5ff8e09f 100644 --- a/app/Models/Enrollment.php +++ b/app/Models/Enrollment.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; class Enrollment extends BaseModel @@ -27,14 +28,14 @@ class Enrollment extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', + 'student_id' => 'integer', 'class_section_id' => 'integer', - 'parent_id' => 'integer', - 'is_withdrawn' => 'boolean', + 'parent_id' => 'integer', + 'is_withdrawn' => 'boolean', // change to 'datetime' if your columns are DATETIME - 'enrollment_date' => 'date', - 'withdrawal_date' => 'date', + 'enrollment_date' => 'date', + 'withdrawal_date' => 'date', ]; /* Optional relationships */ @@ -68,11 +69,11 @@ class Enrollment extends BaseModel ->select('students.*') ->where('enrollments.parent_id', $parentId); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('enrollments.school_year', $schoolYear); } - if (! empty($semester)) { + if (!empty($semester)) { $q->where('enrollments.semester', $semester); } @@ -91,10 +92,10 @@ class Enrollment extends BaseModel ->where('enrollments.parent_id', $parentId) ->where(function ($w) { $w->where('enrollments.enrollment_status', 'enrolled') - ->orWhere('enrollments.enrollment_status', 'payment pending'); + ->orWhere('enrollments.enrollment_status', 'payment pending'); }); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('enrollments.school_year', $schoolYear); } @@ -117,4 +118,4 @@ class Enrollment extends BaseModel return $row?->enrollment_status; } -} +} \ No newline at end of file diff --git a/app/Models/Event.php b/app/Models/Event.php index 38bccfc2..4eae8188 100644 --- a/app/Models/Event.php +++ b/app/Models/Event.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class Event extends BaseModel { protected $table = 'events'; @@ -24,9 +26,9 @@ class Event extends BaseModel ]; protected $casts = [ - 'amount' => 'decimal:2', // adjust precision if needed + 'amount' => 'decimal:2', // adjust precision if needed 'expiration_date' => 'date', // change to 'datetime' if stored as DATETIME - 'created_by' => 'integer', + 'created_by' => 'integer', ]; /* Optional relationships */ @@ -52,7 +54,7 @@ class Event extends BaseModel $q = static::query() ->whereDate('expiration_date', '>=', now()->toDateString()); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('school_year', $schoolYear); } @@ -65,9 +67,9 @@ class Event extends BaseModel public static function getEventsByName(string $name, ?string $schoolYear = null) { $q = static::query() - ->where('event_name', 'like', '%'.$name.'%'); + ->where('event_name', 'like', '%' . $name . '%'); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('school_year', $schoolYear); } @@ -81,7 +83,7 @@ class Event extends BaseModel { $q = static::query(); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('school_year', $schoolYear); } @@ -94,7 +96,6 @@ class Event extends BaseModel public static function addEvent(array $data): int { $row = static::create($data); - return (int) $row->id; } @@ -105,7 +106,7 @@ class Event extends BaseModel { $q = static::query()->whereDate('expiration_date', $date); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('school_year', $schoolYear); } @@ -120,11 +121,11 @@ class Event extends BaseModel $q = static::query() ->whereDate('expiration_date', '>=', now()->toDateString()); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('school_year', $schoolYear); } - if (! empty($semester)) { + if (!empty($semester)) { $q->where('semester', $semester); } @@ -138,7 +139,7 @@ class Event extends BaseModel { $q = static::query()->whereKey($id); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('school_year', $schoolYear); } @@ -152,7 +153,7 @@ class Event extends BaseModel { $q = static::query()->whereKey($id); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('school_year', $schoolYear); } @@ -166,10 +167,10 @@ class Event extends BaseModel { $q = static::query()->whereKey($id); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('school_year', $schoolYear); } return (bool) $q->delete(); } -} +} \ No newline at end of file diff --git a/app/Models/EventCharge.php b/app/Models/EventCharge.php index 7b6a7ebd..5f754a2e 100644 --- a/app/Models/EventCharge.php +++ b/app/Models/EventCharge.php @@ -2,4 +2,6 @@ namespace App\Models; -class EventCharge extends EventCharges {} +class EventCharge extends EventCharges +{ +} diff --git a/app/Models/EventCharges.php b/app/Models/EventCharges.php index 6eb27912..fd6b17e6 100644 --- a/app/Models/EventCharges.php +++ b/app/Models/EventCharges.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; class EventCharges extends BaseModel @@ -40,12 +41,12 @@ class EventCharges extends BaseModel ]; protected $casts = [ - 'event_id' => 'integer', - 'parent_id' => 'integer', - 'student_id' => 'integer', - 'participation' => 'boolean', // change if stored as string/enum - 'charged' => 'boolean', // change if stored as string/enum - 'updated_by' => 'integer', + 'event_id' => 'integer', + 'parent_id' => 'integer', + 'student_id' => 'integer', + 'participation' => 'boolean', // change if stored as string/enum + 'charged' => 'boolean', // change if stored as string/enum + 'updated_by' => 'integer', ]; /* Optional relationships */ @@ -74,15 +75,15 @@ class EventCharges extends BaseModel ->leftJoin('events', 'events.id', '=', 'event_charges.event_id') ->select('event_charges.*', 'events.event_name', 'events.amount'); - if (! empty($parentId)) { + if (!empty($parentId)) { $q->where('event_charges.parent_id', $parentId); } - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('event_charges.school_year', $schoolYear); } - if (! empty($semester)) { + if (!empty($semester)) { $q->where('event_charges.semester', $semester); } diff --git a/app/Models/Exam.php b/app/Models/Exam.php index 3bc386dc..2cf1ec1f 100644 --- a/app/Models/Exam.php +++ b/app/Models/Exam.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class Exam extends BaseModel { protected $table = 'exams'; @@ -14,7 +16,6 @@ class Exam extends BaseModel * We'll keep auto created_at, no updated_at: */ public $timestamps = true; - const UPDATED_AT = null; // ✅ no updated_at column protected $fillable = [ @@ -26,8 +27,8 @@ class Exam extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', - 'school_id' => 'integer', + 'student_id' => 'integer', + 'school_id' => 'integer', 'class_section_id' => 'integer', ]; @@ -41,4 +42,4 @@ class Exam extends BaseModel { return $this->belongsTo(ClassSection::class, 'class_section_id'); } -} +} \ No newline at end of file diff --git a/app/Models/ExamDraft.php b/app/Models/ExamDraft.php index 577af180..50e69551 100644 --- a/app/Models/ExamDraft.php +++ b/app/Models/ExamDraft.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class ExamDraft extends BaseModel { protected $table = 'exam_drafts'; @@ -41,15 +43,15 @@ class ExamDraft extends BaseModel ]; protected $casts = [ - 'teacher_id' => 'integer', - 'class_section_id' => 'integer', - 'admin_id' => 'integer', - 'is_legacy' => 'boolean', + 'teacher_id' => 'integer', + 'class_section_id' => 'integer', + 'admin_id' => 'integer', + 'is_legacy' => 'boolean', - 'version' => 'integer', + 'version' => 'integer', 'previous_draft_id' => 'integer', - 'reviewed_at' => 'datetime', + 'reviewed_at' => 'datetime', ]; /** @@ -63,7 +65,7 @@ class ExamDraft extends BaseModel */ public function forceSave(array $attributes = []): bool { - if (! empty($attributes)) { + if (!empty($attributes)) { $this->fill($attributes); } diff --git a/app/Models/Expense.php b/app/Models/Expense.php index f5e98940..c7f841be 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; class Expense extends BaseModel @@ -30,14 +31,14 @@ class Expense extends BaseModel ]; protected $casts = [ - 'amount' => 'decimal:2', // adjust precision if needed - 'date_of_purchase' => 'date', // change to 'datetime' if stored as DATETIME + 'amount' => 'decimal:2', // adjust precision if needed + 'date_of_purchase'=> 'date', // change to 'datetime' if stored as DATETIME - 'purchased_by' => 'integer', - 'added_by' => 'integer', - 'reimbursement_id' => 'integer', - 'approved_by' => 'integer', - 'updated_by' => 'integer', + 'purchased_by' => 'integer', + 'added_by' => 'integer', + 'reimbursement_id'=> 'integer', + 'approved_by' => 'integer', + 'updated_by' => 'integer', ]; /* Optional relationships */ @@ -70,7 +71,7 @@ class Expense extends BaseModel public static function getReimbursedExpensesWithDetails(array $filters = []) { $q = DB::table('expenses') - ->selectRaw(' + ->selectRaw(" expenses.*, r.id AS reimb_id, r.amount AS reimb_amount, r.reimbursement_method, r.check_number, @@ -79,24 +80,24 @@ class Expense extends BaseModel r.reimbursed_to AS reimb_recipient_id, reimb.firstname AS reimb_firstname, reimb.lastname AS reimb_lastname, approver.firstname AS approver_firstname, approver.lastname AS approver_lastname - ') + ") ->join('reimbursements as r', 'r.expense_id', '=', 'expenses.id') ->leftJoin('users as reimb', 'reimb.id', '=', 'r.reimbursed_to') ->leftJoin('users as approver', 'approver.id', '=', 'r.approved_by'); - if (! empty($filters['school_year'])) { + if (!empty($filters['school_year'])) { $q->where('r.school_year', $filters['school_year']); } - if (! empty($filters['semester'])) { + if (!empty($filters['semester'])) { $q->where('r.semester', $filters['semester']); } - if (! empty($filters['status'])) { + if (!empty($filters['status'])) { $q->where('r.status', $filters['status']); } - if (! empty($filters['user_id'])) { + if (!empty($filters['user_id'])) { $q->where('r.reimbursed_to', $filters['user_id']); } return $q->orderByDesc('r.created_at'); } -} +} \ No newline at end of file diff --git a/app/Models/Family.php b/app/Models/Family.php index 0b5aa216..fdc35785 100644 --- a/app/Models/Family.php +++ b/app/Models/Family.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class Family extends BaseModel { protected $table = 'families'; @@ -38,4 +40,4 @@ class Family extends BaseModel { return $this->hasMany(FamilyCommPref::class, 'family_id'); } -} +} \ No newline at end of file diff --git a/app/Models/FamilyCommPref.php b/app/Models/FamilyCommPref.php index 20211ac0..54133289 100644 --- a/app/Models/FamilyCommPref.php +++ b/app/Models/FamilyCommPref.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class FamilyCommPref extends BaseModel { protected $table = 'family_comm_prefs'; @@ -18,10 +20,10 @@ class FamilyCommPref extends BaseModel ]; protected $casts = [ - 'family_id' => 'integer', - 'via_email' => 'boolean', - 'via_sms' => 'boolean', - 'cc_all_guardians' => 'boolean', + 'family_id' => 'integer', + 'via_email' => 'boolean', + 'via_sms' => 'boolean', + 'cc_all_guardians' => 'boolean', ]; // Optional relationship @@ -29,4 +31,4 @@ class FamilyCommPref extends BaseModel { return $this->belongsTo(Family::class, 'family_id'); } -} +} \ No newline at end of file diff --git a/app/Models/FamilyGuardian.php b/app/Models/FamilyGuardian.php index 8bd3a5eb..b4d957ac 100644 --- a/app/Models/FamilyGuardian.php +++ b/app/Models/FamilyGuardian.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class FamilyGuardian extends BaseModel { protected $table = 'family_guardians'; @@ -20,11 +22,11 @@ class FamilyGuardian extends BaseModel ]; protected $casts = [ - 'family_id' => 'integer', - 'user_id' => 'integer', - 'is_primary' => 'boolean', - 'receive_emails' => 'boolean', - 'receive_sms' => 'boolean', + 'family_id' => 'integer', + 'user_id' => 'integer', + 'is_primary' => 'boolean', + 'receive_emails' => 'boolean', + 'receive_sms' => 'boolean', ]; // Optional relationships @@ -37,4 +39,4 @@ class FamilyGuardian extends BaseModel { return $this->belongsTo(User::class, 'user_id'); } -} +} \ No newline at end of file diff --git a/app/Models/FamilyStudent.php b/app/Models/FamilyStudent.php index 80c3f880..c472f3b1 100644 --- a/app/Models/FamilyStudent.php +++ b/app/Models/FamilyStudent.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; class FamilyStudent extends BaseModel @@ -19,9 +20,9 @@ class FamilyStudent extends BaseModel ]; protected $casts = [ - 'family_id' => 'integer', - 'student_id' => 'integer', - 'is_primary_home' => 'boolean', + 'family_id' => 'integer', + 'student_id' => 'integer', + 'is_primary_home' => 'boolean', ]; /* Optional relationships */ @@ -52,4 +53,4 @@ class FamilyStudent extends BaseModel ->map(fn ($r) => (array) $r) ->all(); } -} +} \ No newline at end of file diff --git a/app/Models/FinalExam.php b/app/Models/FinalExam.php index 23f8abb1..499d7571 100644 --- a/app/Models/FinalExam.php +++ b/app/Models/FinalExam.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class FinalExam extends BaseModel { protected $table = 'final_exam'; @@ -31,19 +33,19 @@ class FinalExam extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', - 'school_id' => 'integer', + 'student_id' => 'integer', + 'school_id' => 'integer', 'class_section_id' => 'integer', - 'updated_by' => 'integer', + 'updated_by' => 'integer', // score is often numeric; adjust if yours is integer - 'score' => 'decimal:2', - 'max_points' => 'decimal:2', - 'locked_by' => 'integer', - 'locked_at' => 'datetime', + 'score' => 'decimal:2', + 'max_points' => 'decimal:2', + 'locked_by' => 'integer', + 'locked_at' => 'datetime', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* Optional relationships */ @@ -80,4 +82,4 @@ class FinalExam extends BaseModel return $row?->score; } -} +} \ No newline at end of file diff --git a/app/Models/FinalScore.php b/app/Models/FinalScore.php index 2b6ef597..88e4e46a 100644 --- a/app/Models/FinalScore.php +++ b/app/Models/FinalScore.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class FinalScore extends BaseModel { protected $table = 'final_score'; @@ -25,11 +27,11 @@ class FinalScore extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', - 'school_id' => 'integer', + 'student_id' => 'integer', + 'school_id' => 'integer', 'class_section_id' => 'integer', - 'teacher_id' => 'integer', - 'score' => 'decimal:2', // change to 'integer' if score is whole number + 'teacher_id' => 'integer', + 'score' => 'decimal:2', // change to 'integer' if score is whole number ]; /* Optional relationships */ @@ -62,4 +64,4 @@ class FinalScore extends BaseModel return $row?->score; } -} +} \ No newline at end of file diff --git a/app/Models/FinanceBalanceCarryforward.php b/app/Models/FinanceBalanceCarryforward.php index cee21143..776b63b8 100644 --- a/app/Models/FinanceBalanceCarryforward.php +++ b/app/Models/FinanceBalanceCarryforward.php @@ -5,8 +5,6 @@ namespace App\Models; class FinanceBalanceCarryforward extends BaseModel { protected $guarded = []; - protected $table = 'finance_balance_carryforwards'; - protected $casts = ['source_invoice_ids_json' => 'array', 'metadata_json' => 'array']; } diff --git a/app/Models/FinanceFollowUpNote.php b/app/Models/FinanceFollowUpNote.php index 34ecbdd5..bd292657 100644 --- a/app/Models/FinanceFollowUpNote.php +++ b/app/Models/FinanceFollowUpNote.php @@ -5,6 +5,5 @@ namespace App\Models; class FinanceFollowUpNote extends BaseModel { protected $guarded = []; - protected $table = 'finance_follow_up_notes'; } diff --git a/app/Models/FinanceNotificationLog.php b/app/Models/FinanceNotificationLog.php index 7a9e58eb..d4145137 100644 --- a/app/Models/FinanceNotificationLog.php +++ b/app/Models/FinanceNotificationLog.php @@ -5,6 +5,5 @@ namespace App\Models; class FinanceNotificationLog extends BaseModel { protected $guarded = []; - protected $table = 'finance_notification_logs'; } diff --git a/app/Models/FinanceNotificationPreference.php b/app/Models/FinanceNotificationPreference.php index 3544107d..4a05d1a5 100644 --- a/app/Models/FinanceNotificationPreference.php +++ b/app/Models/FinanceNotificationPreference.php @@ -5,6 +5,5 @@ namespace App\Models; class FinanceNotificationPreference extends BaseModel { protected $guarded = []; - protected $table = 'finance_notification_preferences'; } diff --git a/app/Models/FinanceReceiptSequence.php b/app/Models/FinanceReceiptSequence.php index 94494dcc..28a2d452 100644 --- a/app/Models/FinanceReceiptSequence.php +++ b/app/Models/FinanceReceiptSequence.php @@ -5,6 +5,5 @@ namespace App\Models; class FinanceReceiptSequence extends BaseModel { protected $guarded = []; - protected $table = 'finance_receipt_sequences'; } diff --git a/app/Models/GradingLock.php b/app/Models/GradingLock.php index 24865d70..314135a9 100644 --- a/app/Models/GradingLock.php +++ b/app/Models/GradingLock.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class GradingLock extends BaseModel { protected $table = 'grading_locks'; @@ -22,9 +24,9 @@ class GradingLock extends BaseModel protected $casts = [ 'class_section_id' => 'integer', - 'is_locked' => 'boolean', - 'locked_by' => 'integer', - 'locked_at' => 'datetime', + 'is_locked' => 'boolean', + 'locked_by' => 'integer', + 'locked_at' => 'datetime', ]; /* Optional relationships */ @@ -61,7 +63,6 @@ class GradingLock extends BaseModel public static function isLocked(int $classSectionId, string $semester, string $schoolYear): bool { $row = static::getLock($classSectionId, $semester, $schoolYear); - return (bool) ($row?->is_locked ?? false); } -} +} \ No newline at end of file diff --git a/app/Models/Homework.php b/app/Models/Homework.php index af827e8a..be7b8ecb 100644 --- a/app/Models/Homework.php +++ b/app/Models/Homework.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; class Homework extends BaseModel @@ -34,20 +35,20 @@ class Homework extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', - 'school_id' => 'integer', + 'student_id' => 'integer', + 'school_id' => 'integer', 'class_section_id' => 'integer', - 'updated_by' => 'integer', - 'homework_index' => 'integer', + 'updated_by' => 'integer', + 'homework_index' => 'integer', // keep numeric; change to 'integer' if your scores are whole numbers - 'score' => 'decimal:2', - 'max_points' => 'decimal:2', - 'locked_by' => 'integer', - 'locked_at' => 'datetime', + 'score' => 'decimal:2', + 'max_points' => 'decimal:2', + 'locked_by' => 'integer', + 'locked_at' => 'datetime', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* Optional relationships */ @@ -92,18 +93,10 @@ class Homework extends BaseModel foreach ($rows as $r) { $score = $r->score ?? null; - if ($score === null) { - continue; - } - if (is_string($score) && trim($score) === '') { - continue; - } - if ($score === '') { - continue; - } - if (! is_numeric($score)) { - continue; - } + if ($score === null) continue; + if (is_string($score) && trim($score) === '') continue; + if ($score === '') continue; + if (!is_numeric($score)) continue; $total += (float) $score; $count++; @@ -115,4 +108,4 @@ class Homework extends BaseModel return round($total / $count, 2); } -} +} \ No newline at end of file diff --git a/app/Models/Incident.php b/app/Models/Incident.php index 5121d5d2..3ab7d922 100644 --- a/app/Models/Incident.php +++ b/app/Models/Incident.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class Incident extends BaseModel { protected $table = 'incident'; @@ -30,11 +32,11 @@ class Incident extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', - 'updated_by_open' => 'integer', - 'updated_by_closed' => 'integer', + 'student_id' => 'integer', + 'updated_by_open' => 'integer', + 'updated_by_closed' => 'integer', 'updated_by_canceled' => 'integer', - 'incident_datetime' => 'datetime', + 'incident_datetime' => 'datetime', ]; /* Optional relationships */ diff --git a/app/Models/InventoryCategory.php b/app/Models/InventoryCategory.php index c0901238..eb0cfbcb 100644 --- a/app/Models/InventoryCategory.php +++ b/app/Models/InventoryCategory.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class InventoryCategory extends BaseModel { protected $table = 'inventory_categories'; @@ -37,4 +39,4 @@ class InventoryCategory extends BaseModel ->get() ->toArray(); } -} +} \ No newline at end of file diff --git a/app/Models/InventoryItem.php b/app/Models/InventoryItem.php index 60e0af1e..51c0dbbb 100644 --- a/app/Models/InventoryItem.php +++ b/app/Models/InventoryItem.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class InventoryItem extends BaseModel { protected $table = 'inventory_items'; @@ -31,14 +33,14 @@ class InventoryItem extends BaseModel ]; protected $casts = [ - 'category_id' => 'integer', - 'quantity' => 'integer', - 'updated_by' => 'integer', + 'category_id' => 'integer', + 'quantity' => 'integer', + 'updated_by' => 'integer', - 'good_qty' => 'integer', - 'needs_repair_qty' => 'integer', - 'need_replace_qty' => 'integer', - 'cannot_find_qty' => 'integer', + 'good_qty' => 'integer', + 'needs_repair_qty' => 'integer', + 'need_replace_qty' => 'integer', + 'cannot_find_qty' => 'integer', ]; /* Optional relationships */ @@ -46,4 +48,4 @@ class InventoryItem extends BaseModel { return $this->belongsTo(InventoryCategory::class, 'category_id'); } -} +} \ No newline at end of file diff --git a/app/Models/InventoryMovement.php b/app/Models/InventoryMovement.php index f1c1f13a..b6bdeda9 100644 --- a/app/Models/InventoryMovement.php +++ b/app/Models/InventoryMovement.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class InventoryMovement extends BaseModel { protected $table = 'inventory_movements'; @@ -24,12 +26,12 @@ class InventoryMovement extends BaseModel ]; protected $casts = [ - 'item_id' => 'integer', - 'qty_change' => 'integer', - 'performed_by' => 'integer', - 'teacher_id' => 'integer', - 'student_id' => 'integer', - 'class_section_id' => 'integer', + 'item_id' => 'integer', + 'qty_change' => 'integer', + 'performed_by' => 'integer', + 'teacher_id' => 'integer', + 'student_id' => 'integer', + 'class_section_id'=> 'integer', ]; /* Optional relationships */ @@ -57,4 +59,4 @@ class InventoryMovement extends BaseModel { return $this->belongsTo(ClassSection::class, 'class_section_id'); } -} +} \ No newline at end of file diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 38a28c37..f918522c 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; @@ -34,19 +35,19 @@ class Invoice extends BaseModel ]; protected $casts = [ - 'parent_id' => 'integer', - 'updated_by' => 'integer', + 'parent_id' => 'integer', + 'updated_by' => 'integer', 'has_discount' => 'boolean', 'total_amount' => 'decimal:2', - 'balance' => 'decimal:2', - 'paid_amount' => 'decimal:2', + 'balance' => 'decimal:2', + 'paid_amount' => 'decimal:2', - 'issue_date' => 'datetime', - 'due_date' => 'datetime', + 'issue_date' => 'datetime', + 'due_date' => 'datetime', // created_at/updated_at exist but are DB-managed; you can still cast if you like: - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* Optional relationships */ @@ -83,18 +84,13 @@ class Invoice extends BaseModel private function normalizeDateTimes(): void { foreach (['issue_date', 'due_date', 'created_at', 'updated_at'] as $field) { - if (! $this->isDirty($field)) { - continue; - } + if (!$this->isDirty($field)) continue; $val = $this->{$field}; if ($val === null || $val === '' || $val === '0000-00-00' || $val === '0000-00-00 00:00:00') { // keep NULL for due_date; keep other values as-is (DB defaults/triggers) - if ($field === 'due_date') { - $this->{$field} = null; - } - + if ($field === 'due_date') $this->{$field} = null; continue; } @@ -112,14 +108,11 @@ class Invoice extends BaseModel } $s = trim((string) $raw); - if ($s === '') { - return null; - } + if ($s === '') return null; // strict datetime try { $dt = Carbon::createFromFormat('Y-m-d H:i:s', $s, 'UTC'); - return $dt->utc()->format('Y-m-d H:i:s'); } catch (\Throwable $e) { // ignore @@ -128,7 +121,6 @@ class Invoice extends BaseModel // date-only sneaks in => store at 12:00:00 try { $d = Carbon::createFromFormat('Y-m-d', $s, 'UTC')->setTime(12, 0, 0); - return $d->utc()->format('Y-m-d H:i:s'); } catch (\Throwable $e) { // ignore @@ -215,7 +207,7 @@ class Invoice extends BaseModel ->selectRaw('(SELECT COALESCE(SUM(du.discount_amount),0) FROM discount_usages du WHERE du.invoice_id = i.id) AS discount') ->where('i.parent_id', $parentId); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('i.school_year', $schoolYear); } @@ -250,12 +242,10 @@ class Invoice extends BaseModel public static function getInvoicesByUserIds(array $parentIds, string $schoolYear): array { $parentIds = array_values(array_unique(array_map('intval', array_filter($parentIds)))); - if (empty($parentIds)) { - return []; - } + if (empty($parentIds)) return []; return DB::table('invoices as i') - ->select(['i.id', 'i.parent_id', 'i.invoice_number', 'i.status', 'i.balance', 'i.total_amount', 'i.issue_date', 'i.due_date']) + ->select(['i.id','i.parent_id','i.invoice_number','i.status','i.balance','i.total_amount','i.issue_date','i.due_date']) ->selectRaw('(SELECT COALESCE(SUM(du.discount_amount),0) FROM discount_usages du WHERE du.invoice_id = i.id) AS discount') ->whereIn('i.parent_id', $parentIds) ->where('i.school_year', $schoolYear) @@ -269,12 +259,10 @@ class Invoice extends BaseModel public static function getAllInvoicesByUserIds(array $parentIds, string $schoolYear): array { $parentIds = array_values(array_unique(array_map('intval', array_filter($parentIds)))); - if (empty($parentIds)) { - return []; - } + if (empty($parentIds)) return []; return DB::table('invoices as i') - ->select(['i.id', 'i.parent_id', 'i.invoice_number', 'i.status', 'i.balance', 'i.issue_date']) + ->select(['i.id','i.parent_id','i.invoice_number','i.status','i.balance','i.issue_date']) ->selectRaw('(SELECT COALESCE(SUM(du.discount_amount),0) FROM discount_usages du WHERE du.invoice_id = i.id) AS discount') ->whereIn('i.parent_id', $parentIds) ->where('i.school_year', $schoolYear) @@ -326,10 +314,10 @@ class Invoice extends BaseModel $affected = DB::table('invoices') ->where('id', $invoiceId) ->update([ - 'total_amount' => DB::raw('GREATEST(total_amount - '.$amount.', 0)'), - 'balance' => DB::raw('GREATEST(balance - '.$amount.', 0)'), + 'total_amount' => DB::raw('GREATEST(total_amount - ' . $amount . ', 0)'), + 'balance' => DB::raw('GREATEST(balance - ' . $amount . ', 0)'), ]); return $affected >= 0; } -} +} \ No newline at end of file diff --git a/app/Models/InvoiceEvent.php b/app/Models/InvoiceEvent.php index 2ee0036a..8613000b 100644 --- a/app/Models/InvoiceEvent.php +++ b/app/Models/InvoiceEvent.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class InvoiceEvent extends BaseModel { protected $table = 'invoice_event'; @@ -22,9 +24,9 @@ class InvoiceEvent extends BaseModel ]; protected $casts = [ - 'invoice_id' => 'integer', - 'amount' => 'decimal:2', // adjust precision if needed - 'updated_by' => 'integer', + 'invoice_id' => 'integer', + 'amount' => 'decimal:2', // adjust precision if needed + 'updated_by' => 'integer', ]; /* Optional relationships */ @@ -37,4 +39,4 @@ class InvoiceEvent extends BaseModel { return $this->belongsTo(User::class, 'updated_by'); } -} +} \ No newline at end of file diff --git a/app/Models/InvoiceInstallment.php b/app/Models/InvoiceInstallment.php index daec4dd9..e9c0bb25 100644 --- a/app/Models/InvoiceInstallment.php +++ b/app/Models/InvoiceInstallment.php @@ -5,6 +5,5 @@ namespace App\Models; class InvoiceInstallment extends BaseModel { protected $guarded = []; - protected $table = 'invoice_installments'; } diff --git a/app/Models/InvoiceInstallmentPlan.php b/app/Models/InvoiceInstallmentPlan.php index eadc6987..610827a3 100644 --- a/app/Models/InvoiceInstallmentPlan.php +++ b/app/Models/InvoiceInstallmentPlan.php @@ -5,6 +5,5 @@ namespace App\Models; class InvoiceInstallmentPlan extends BaseModel { protected $guarded = []; - protected $table = 'invoice_installment_plans'; } diff --git a/app/Models/InvoiceStudentList.php b/app/Models/InvoiceStudentList.php index 0b2dab93..256bd20b 100644 --- a/app/Models/InvoiceStudentList.php +++ b/app/Models/InvoiceStudentList.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class InvoiceStudentList extends BaseModel { protected $table = 'invoice_students_list'; @@ -25,8 +27,8 @@ class InvoiceStudentList extends BaseModel protected $casts = [ 'invoice_id' => 'integer', 'student_id' => 'integer', - 'school_id' => 'integer', - 'enrolled' => 'boolean', + 'school_id' => 'integer', + 'enrolled' => 'boolean', ]; /* Optional relationships */ @@ -39,4 +41,4 @@ class InvoiceStudentList extends BaseModel { return $this->belongsTo(Student::class, 'student_id'); } -} +} \ No newline at end of file diff --git a/app/Models/IpAttempt.php b/app/Models/IpAttempt.php index ca1e6d75..b2a4175d 100644 --- a/app/Models/IpAttempt.php +++ b/app/Models/IpAttempt.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class IpAttempt extends BaseModel { protected $table = 'ip_attempts'; @@ -19,9 +21,9 @@ class IpAttempt extends BaseModel ]; protected $casts = [ - 'attempts' => 'integer', + 'attempts' => 'integer', 'last_attempt_at' => 'datetime', - 'blocked_until' => 'datetime', + 'blocked_until' => 'datetime', ]; /** @@ -51,7 +53,6 @@ class IpAttempt extends BaseModel public static function insertIpAttempt(array $data): int { $row = static::query()->create($data); - return (int) $row->id; } -} +} \ No newline at end of file diff --git a/app/Models/LateSlipLog.php b/app/Models/LateSlipLog.php index 85be8c58..c8103abd 100644 --- a/app/Models/LateSlipLog.php +++ b/app/Models/LateSlipLog.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\QueryException; use Illuminate\Support\Facades\Log; @@ -27,10 +28,10 @@ class LateSlipLog extends BaseModel protected $casts = [ 'printed_by' => 'integer', - 'slip_date' => 'date', // slip_date is Y-m-d + 'slip_date' => 'date', // slip_date is Y-m-d 'printed_at' => 'datetime', // time_in is often stored as TIME or string; keep as string unless you store as DATETIME - 'time_in' => 'string', + 'time_in' => 'string', ]; /** @@ -40,30 +41,27 @@ class LateSlipLog extends BaseModel public static function logSlip(array $data, ?int $printedBy): bool { $row = [ - 'school_year' => (string) ($data['school_year'] ?? ''), - 'semester' => (string) ($data['semester'] ?? ''), - 'student_name' => (string) ($data['student_name'] ?? ''), - 'slip_date' => $data['slip_date'] ?? null, // Y-m-d - 'time_in' => $data['time_in'] ?? null, // H:i:s - 'grade' => (string) ($data['grade'] ?? ''), - 'reason' => (string) ($data['reason'] ?? ''), - 'admin_name' => (string) ($data['admin_name'] ?? ''), - 'printed_by' => $printedBy, - 'printed_at' => now(), // use UTC if your app timezone is UTC + 'school_year' => (string)($data['school_year'] ?? ''), + 'semester' => (string)($data['semester'] ?? ''), + 'student_name' => (string)($data['student_name'] ?? ''), + 'slip_date' => $data['slip_date'] ?? null, // Y-m-d + 'time_in' => $data['time_in'] ?? null, // H:i:s + 'grade' => (string)($data['grade'] ?? ''), + 'reason' => (string)($data['reason'] ?? ''), + 'admin_name' => (string)($data['admin_name'] ?? ''), + 'printed_by' => $printedBy, + 'printed_at' => now(), // use UTC if your app timezone is UTC ]; try { // create() returns model; treat as success if created $created = static::query()->create($row); - - return ! empty($created->id); + return !empty($created->id); } catch (QueryException $e) { - Log::error('LateSlipLog::logSlip failed: '.$e->getMessage()); - + Log::error('LateSlipLog::logSlip failed: ' . $e->getMessage()); return false; } catch (\Throwable $e) { - Log::error('LateSlipLog::logSlip failed: '.$e->getMessage()); - + Log::error('LateSlipLog::logSlip failed: ' . $e->getMessage()); return false; } } @@ -73,4 +71,4 @@ class LateSlipLog extends BaseModel { return $this->belongsTo(User::class, 'printed_by'); } -} +} \ No newline at end of file diff --git a/app/Models/LoginActivity.php b/app/Models/LoginActivity.php index df5cb17e..a2995895 100644 --- a/app/Models/LoginActivity.php +++ b/app/Models/LoginActivity.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class LoginActivity extends BaseModel { protected $table = 'login_activity'; @@ -23,8 +25,8 @@ class LoginActivity extends BaseModel ]; protected $casts = [ - 'user_id' => 'integer', - 'login_time' => 'datetime', + 'user_id' => 'integer', + 'login_time' => 'datetime', 'logout_time' => 'datetime', ]; @@ -44,4 +46,4 @@ class LoginActivity extends BaseModel ->limit(max(1, $limit)) ->get(); } -} +} \ No newline at end of file diff --git a/app/Models/ManualPayment.php b/app/Models/ManualPayment.php index bece370d..a5edf9e9 100644 --- a/app/Models/ManualPayment.php +++ b/app/Models/ManualPayment.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class ManualPayment extends BaseModel { protected $table = 'manual_payments'; @@ -21,7 +23,7 @@ class ManualPayment extends BaseModel ]; protected $casts = [ - 'amount' => 'decimal:2', // adjust precision if needed + 'amount' => 'decimal:2', // adjust precision if needed 'created_at' => 'datetime', ]; @@ -30,4 +32,4 @@ class ManualPayment extends BaseModel { return $this->belongsTo(Invoice::class, 'invoice_number', 'invoice_number'); } -} +} \ No newline at end of file diff --git a/app/Models/Message.php b/app/Models/Message.php index 951a1c66..ed7dcbdc 100644 --- a/app/Models/Message.php +++ b/app/Models/Message.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class Message extends BaseModel { protected $table = 'messages'; @@ -26,13 +28,13 @@ class Message extends BaseModel ]; protected $casts = [ - 'sender_id' => 'integer', - 'recipient_id' => 'integer', - 'read_status' => 'boolean', + 'sender_id' => 'integer', + 'recipient_id' => 'integer', + 'read_status' => 'boolean', 'message_number' => 'integer', - 'sent_datetime' => 'datetime', - 'read_datetime' => 'datetime', + 'sent_datetime' => 'datetime', + 'read_datetime' => 'datetime', ]; /* Optional relationships */ @@ -64,7 +66,7 @@ class Message extends BaseModel $affected = static::query() ->whereKey($messageId) ->update([ - 'read_status' => 1, + 'read_status' => 1, 'read_datetime' => now(), // set app timezone (configure to UTC if desired) ]); @@ -119,7 +121,7 @@ class Message extends BaseModel return static::query() ->where(function ($q) use ($userId) { $q->where('sender_id', $userId) - ->orWhere('recipient_id', $userId); + ->orWhere('recipient_id', $userId); }) ->where('status', 'trashed') ->orderByDesc('sent_datetime') @@ -130,10 +132,10 @@ class Message extends BaseModel { $q = static::query()->where('semester', $semester); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('school_year', $schoolYear); } return $q->orderByDesc('sent_datetime')->get(); } -} +} \ No newline at end of file diff --git a/app/Models/MidtermExam.php b/app/Models/MidtermExam.php index 5feaeb8d..9ca5eace 100644 --- a/app/Models/MidtermExam.php +++ b/app/Models/MidtermExam.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class MidtermExam extends BaseModel { protected $table = 'midterm_exam'; @@ -31,19 +33,19 @@ class MidtermExam extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', - 'school_id' => 'integer', + 'student_id' => 'integer', + 'school_id' => 'integer', 'class_section_id' => 'integer', - 'updated_by' => 'integer', + 'updated_by' => 'integer', // score can be decimal; change to 'integer' if it's whole number - 'score' => 'decimal:2', - 'max_points' => 'decimal:2', - 'locked_by' => 'integer', - 'locked_at' => 'datetime', + 'score' => 'decimal:2', + 'max_points' => 'decimal:2', + 'locked_by' => 'integer', + 'locked_at' => 'datetime', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* Optional relationships */ @@ -83,4 +85,4 @@ class MidtermExam extends BaseModel return $row?->score; } -} +} \ No newline at end of file diff --git a/app/Models/MissingScoreOverride.php b/app/Models/MissingScoreOverride.php index 0831fe47..cc0bf55e 100644 --- a/app/Models/MissingScoreOverride.php +++ b/app/Models/MissingScoreOverride.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; class MissingScoreOverride extends BaseModel @@ -25,11 +26,11 @@ class MissingScoreOverride extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', + 'student_id' => 'integer', 'class_section_id' => 'integer', - 'item_index' => 'integer', - 'is_allowed' => 'boolean', - 'updated_by' => 'integer', + 'item_index' => 'integer', + 'is_allowed' => 'boolean', + 'updated_by' => 'integer', ]; /** @@ -100,12 +101,12 @@ class MissingScoreOverride extends BaseModel ->where('school_year', $schoolYear) ->where('item_type', $itemType); - if (! empty($studentIds)) { + if (!empty($studentIds)) { $q->whereIn('student_id', array_map('intval', $studentIds)); } if ($itemIndexes !== null) { - if (! empty($itemIndexes)) { + if (!empty($itemIndexes)) { $q->whereIn('item_index', array_map('intval', $itemIndexes)); } else { // legacy behavior: if itemIndexes is provided but empty, do nothing. @@ -127,27 +128,25 @@ class MissingScoreOverride extends BaseModel foreach ($checkedItems as $item) { $sid = (int) ($item['student_id'] ?? 0); - if ($sid <= 0) { - continue; - } + if ($sid <= 0) continue; $rows[] = [ - 'student_id' => $sid, + 'student_id' => $sid, 'class_section_id' => $classSectionId, - 'semester' => $semester, - 'school_year' => $schoolYear, - 'item_type' => $itemType, - 'item_index' => array_key_exists('item_index', $item) ? $item['item_index'] : null, - 'is_allowed' => 1, - 'updated_by' => $updatedBy, - 'created_at' => $now, - 'updated_at' => $now, + 'semester' => $semester, + 'school_year' => $schoolYear, + 'item_type' => $itemType, + 'item_index' => array_key_exists('item_index', $item) ? $item['item_index'] : null, + 'is_allowed' => 1, + 'updated_by' => $updatedBy, + 'created_at' => $now, + 'updated_at' => $now, ]; } - if (! empty($rows)) { + if (!empty($rows)) { DB::table((new static)->getTable())->insert($rows); } }); } -} +} \ No newline at end of file diff --git a/app/Models/NavItem.php b/app/Models/NavItem.php index d425fc15..deb66f32 100644 --- a/app/Models/NavItem.php +++ b/app/Models/NavItem.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\SoftDeletes; class NavItem extends BaseModel @@ -10,7 +11,6 @@ class NavItem extends BaseModel // ✅ legacy: timestamps + soft deletes use SoftDeletes; - public $timestamps = true; protected $fillable = [ @@ -25,8 +25,8 @@ class NavItem extends BaseModel protected $casts = [ 'menu_parent_id' => 'integer', - 'sort_order' => 'integer', - 'is_enabled' => 'boolean', + 'sort_order' => 'integer', + 'is_enabled' => 'boolean', ]; /* Optional relationships */ @@ -55,4 +55,4 @@ class NavItem extends BaseModel ->get() ->toArray(); } -} +} \ No newline at end of file diff --git a/app/Models/Notification.php b/app/Models/Notification.php index 056855ef..94b895b9 100644 --- a/app/Models/Notification.php +++ b/app/Models/Notification.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\SoftDeletes; @@ -11,7 +12,6 @@ class Notification extends BaseModel // ✅ legacy: soft deletes + timestamps use SoftDeletes; - public $timestamps = true; protected $fillable = [ @@ -73,10 +73,10 @@ class Notification extends BaseModel ->where('scheduled_at', '<=', now()) ->where(function ($w) { $w->whereNull('expires_at') - ->orWhere('expires_at', '>', now()); + ->orWhere('expires_at', '>', now()); }); - if (! empty($targetGroup)) { + if (!empty($targetGroup)) { $q->where('target_group', $targetGroup); } @@ -114,10 +114,7 @@ class Notification extends BaseModel public static function restoreNotification(int $id): bool { $row = static::withTrashed()->find($id); - if (! $row) { - return false; - } - + if (!$row) return false; return (bool) $row->restore(); } @@ -132,4 +129,4 @@ class Notification extends BaseModel ->where('expires_at', '<', now()) ->delete(); // soft delete } -} +} \ No newline at end of file diff --git a/app/Models/ParentAttendanceReport.php b/app/Models/ParentAttendanceReport.php index d4ae0341..d559d052 100644 --- a/app/Models/ParentAttendanceReport.php +++ b/app/Models/ParentAttendanceReport.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; class ParentAttendanceReport extends BaseModel @@ -26,10 +27,10 @@ class ParentAttendanceReport extends BaseModel ]; protected $casts = [ - 'parent_id' => 'integer', - 'student_id' => 'integer', - 'class_section_id' => 'integer', - 'report_date' => 'date', + 'parent_id' => 'integer', + 'student_id' => 'integer', + 'class_section_id'=> 'integer', + 'report_date' => 'date', ]; /* Optional relationships */ @@ -67,10 +68,10 @@ class ParentAttendanceReport extends BaseModel $q->where('par.parent_id', $parentId); } - if (! empty($startDate)) { + if (!empty($startDate)) { $q->where('par.report_date', '>=', $startDate); } - if (! empty($endDate)) { + if (!empty($endDate)) { $q->where('par.report_date', '<=', $endDate); } if (is_string($schoolYear) && $schoolYear !== '') { @@ -81,12 +82,12 @@ class ParentAttendanceReport extends BaseModel } $q->leftJoin('students as s', 's.id', '=', 'par.student_id') - ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'par.class_section_id') - ->select('par.*', 's.firstname', 's.lastname', 'cs.class_section_name') - ->orderBy('par.report_date', 'asc') - ->orderBy('par.class_section_id', 'asc') - ->orderBy('par.student_id', 'asc'); + ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'par.class_section_id') + ->select('par.*', 's.firstname', 's.lastname', 'cs.class_section_name') + ->orderBy('par.report_date', 'asc') + ->orderBy('par.class_section_id', 'asc') + ->orderBy('par.student_id', 'asc'); return $q->get()->map(fn ($r) => (array) $r)->all(); } -} +} \ No newline at end of file diff --git a/app/Models/ParentMeetingSchedule.php b/app/Models/ParentMeetingSchedule.php index 6213d9e8..b0d68924 100644 --- a/app/Models/ParentMeetingSchedule.php +++ b/app/Models/ParentMeetingSchedule.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class ParentMeetingSchedule extends BaseModel { protected $table = 'parent_meeting_schedules'; @@ -25,14 +27,14 @@ class ParentMeetingSchedule extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', + 'student_id' => 'integer', 'parent_user_id' => 'integer', - 'created_by' => 'integer', + 'created_by' => 'integer', // if these are DATE/TIME columns: - 'date' => 'date', + 'date' => 'date', // time is typically stored as TIME or string; keep as string unless DATETIME - 'time' => 'string', + 'time' => 'string', ]; /* Optional relationships */ @@ -50,4 +52,4 @@ class ParentMeetingSchedule extends BaseModel { return $this->belongsTo(User::class, 'created_by'); } -} +} \ No newline at end of file diff --git a/app/Models/ParentModel.php b/app/Models/ParentModel.php index dbaba3fc..1313ffad 100644 --- a/app/Models/ParentModel.php +++ b/app/Models/ParentModel.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class ParentModel extends BaseModel { protected $table = 'parents'; @@ -29,4 +31,4 @@ class ParentModel extends BaseModel { return $this->belongsTo(User::class, 'firstparent_id'); } -} +} \ No newline at end of file diff --git a/app/Models/ParentNotification.php b/app/Models/ParentNotification.php index 2a41cc83..d09c6b94 100644 --- a/app/Models/ParentNotification.php +++ b/app/Models/ParentNotification.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class ParentNotification extends BaseModel { protected $table = 'parent_notifications'; @@ -23,7 +25,7 @@ class ParentNotification extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', + 'student_id' => 'integer', // incident_date is stored as Y-m-d in legacy usage 'incident_date' => 'date', ]; @@ -50,7 +52,7 @@ class ParentNotification extends BaseModel ->whereDate('incident_date', $incidentYmd) ->where('channel', $channel); - if (! empty($to)) { + if (!empty($to)) { $q->where('to_address', $to); } @@ -58,4 +60,4 @@ class ParentNotification extends BaseModel return $row && (($row->status ?? '') === 'sent'); } -} +} \ No newline at end of file diff --git a/app/Models/Participation.php b/app/Models/Participation.php index 241d278f..4abe7d62 100644 --- a/app/Models/Participation.php +++ b/app/Models/Participation.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class Participation extends BaseModel { protected $table = 'participation'; @@ -31,19 +33,19 @@ class Participation extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', - 'school_id' => 'integer', + 'student_id' => 'integer', + 'school_id' => 'integer', 'class_section_id' => 'integer', - 'updated_by' => 'integer', + 'updated_by' => 'integer', // score is numeric; change to 'integer' if it is whole number - 'score' => 'decimal:2', - 'max_points' => 'decimal:2', - 'locked_by' => 'integer', - 'locked_at' => 'datetime', + 'score' => 'decimal:2', + 'max_points' => 'decimal:2', + 'locked_by' => 'integer', + 'locked_at' => 'datetime', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* Optional relationships */ @@ -78,25 +80,15 @@ class Participation extends BaseModel } $row = $q->first(); - if (! $row) { - return null; - } + if (!$row) return null; $score = $row->score; - if ($score === null) { - return null; - } - if (is_string($score) && trim($score) === '') { - return null; - } - if ($score === '') { - return null; - } - if (! is_numeric($score)) { - return null; - } + if ($score === null) return null; + if (is_string($score) && trim($score) === '') return null; + if ($score === '') return null; + if (!is_numeric($score)) return null; return (float) $score; } -} +} \ No newline at end of file diff --git a/app/Models/PasswordReset.php b/app/Models/PasswordReset.php index ab6f1330..7857f199 100644 --- a/app/Models/PasswordReset.php +++ b/app/Models/PasswordReset.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class PasswordReset extends BaseModel { protected $table = 'password_resets'; @@ -21,7 +23,6 @@ class PasswordReset extends BaseModel public $timestamps = true; const CREATED_AT = 'created_at'; - const UPDATED_AT = 'expires_at'; protected $fillable = [ @@ -44,4 +45,4 @@ class PasswordReset extends BaseModel // protected $primaryKey = 'id'; // public $incrementing = true; // protected $keyType = 'int'; -} +} \ No newline at end of file diff --git a/app/Models/PasswordResetRequest.php b/app/Models/PasswordResetRequest.php index b136b6f9..f424b1a1 100644 --- a/app/Models/PasswordResetRequest.php +++ b/app/Models/PasswordResetRequest.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class PasswordResetRequest extends BaseModel { protected $table = 'password_reset_requests'; @@ -17,4 +19,4 @@ class PasswordResetRequest extends BaseModel protected $casts = [ 'requested_at' => 'datetime', ]; -} +} \ No newline at end of file diff --git a/app/Models/PayPalPayment.php b/app/Models/PayPalPayment.php index 1c7e56c0..25586958 100644 --- a/app/Models/PayPalPayment.php +++ b/app/Models/PayPalPayment.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class PayPalPayment extends BaseModel { protected $table = 'paypal_payments'; @@ -11,7 +13,6 @@ class PayPalPayment extends BaseModel * In Laravel: enable timestamps but disable UPDATED_AT. */ public $timestamps = true; - const UPDATED_AT = null; protected $fillable = [ @@ -37,10 +38,10 @@ class PayPalPayment extends BaseModel protected $casts = [ 'parent_school_id' => 'integer', - 'amount' => 'decimal:2', - 'paypal_fee' => 'decimal:2', - 'net_amount' => 'decimal:2', - 'synced' => 'boolean', - 'sync_attempts' => 'integer', + 'amount' => 'decimal:2', + 'paypal_fee' => 'decimal:2', + 'net_amount' => 'decimal:2', + 'synced' => 'boolean', + 'sync_attempts' => 'integer', ]; -} +} \ No newline at end of file diff --git a/app/Models/Payment.php b/app/Models/Payment.php index a06bb29b..e57892a2 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; class Payment extends BaseModel @@ -33,16 +34,16 @@ class Payment extends BaseModel ]; protected $casts = [ - 'parent_id' => 'integer', - 'invoice_id' => 'integer', - 'number_of_installments' => 'integer', - 'updated_by' => 'integer', + 'parent_id' => 'integer', + 'invoice_id' => 'integer', + 'number_of_installments' => 'integer', + 'updated_by' => 'integer', - 'total_amount' => 'decimal:2', - 'paid_amount' => 'decimal:2', - 'balance' => 'decimal:2', + 'total_amount' => 'decimal:2', + 'paid_amount' => 'decimal:2', + 'balance' => 'decimal:2', - 'payment_date' => 'datetime', + 'payment_date' => 'datetime', ]; /* Optional relationships */ @@ -83,20 +84,18 @@ class Payment extends BaseModel { /** @var self|null $payment */ $payment = static::query()->find($paymentId); - if (! $payment) { - return false; - } + if (!$payment) return false; - $newBalance = (float) $payment->balance - (float) $amountPaid; + $newBalance = (float)$payment->balance - (float)$amountPaid; // keep precision stable - $paidAmount = (float) $payment->paid_amount + (float) $amountPaid; + $paidAmount = (float)$payment->paid_amount + (float)$amountPaid; $affected = static::query() ->whereKey($paymentId) ->update([ 'paid_amount' => $paidAmount, - 'balance' => $newBalance, + 'balance' => $newBalance, ]); return $affected > 0; @@ -117,21 +116,21 @@ class Payment extends BaseModel public static function generateNewTransactionId(): string { $currentYear = date('Y'); - $prefix = $currentYear.'-'; + $prefix = $currentYear . '-'; $latest = static::query() - ->where('transaction_id', 'like', $prefix.'%') + ->where('transaction_id', 'like', $prefix . '%') ->orderByDesc('transaction_id') ->first(); - if ($latest && ! empty($latest->transaction_id)) { - $lastNumber = (int) str_replace($prefix, '', (string) $latest->transaction_id); + if ($latest && !empty($latest->transaction_id)) { + $lastNumber = (int) str_replace($prefix, '', (string)$latest->transaction_id); $newNumber = $lastNumber + 1; } else { $newNumber = 1; } - return $prefix.str_pad((string) $newNumber, 6, '0', STR_PAD_LEFT); + return $prefix . str_pad((string)$newNumber, 6, '0', STR_PAD_LEFT); } /** @@ -140,13 +139,11 @@ class Payment extends BaseModel */ public static function getPaymentsByInvoice($invoiceIds): array { - if (! is_array($invoiceIds)) { + if (!is_array($invoiceIds)) { $invoiceIds = [$invoiceIds]; } $invoiceIds = array_values(array_unique(array_map('intval', array_filter($invoiceIds)))); - if (empty($invoiceIds)) { - return []; - } + if (empty($invoiceIds)) return []; // Subquery: latest payment_date per invoice (Full/Partial only) $latestSub = DB::table('payments') @@ -158,7 +155,7 @@ class Payment extends BaseModel $rows = DB::table('payments as p') ->joinSub($latestSub, 'latest', function ($join) { $join->on('latest.invoice_id', '=', 'p.invoice_id') - ->on('latest.max_date', '=', 'p.payment_date'); + ->on('latest.max_date', '=', 'p.payment_date'); }) ->whereIn('p.invoice_id', $invoiceIds) ->whereIn('p.status', ['Full', 'Paid', 'Partially Paid']) @@ -172,4 +169,4 @@ class Payment extends BaseModel return $rows->map(fn ($r) => (array) $r)->all(); } -} +} \ No newline at end of file diff --git a/app/Models/PaymentCarryforwardAllocation.php b/app/Models/PaymentCarryforwardAllocation.php index dd01f8cb..0c2118f8 100644 --- a/app/Models/PaymentCarryforwardAllocation.php +++ b/app/Models/PaymentCarryforwardAllocation.php @@ -5,6 +5,5 @@ namespace App\Models; class PaymentCarryforwardAllocation extends BaseModel { protected $guarded = []; - protected $table = 'payment_carryforward_allocations'; } diff --git a/app/Models/PaymentError.php b/app/Models/PaymentError.php index ed41bbd3..753b7a34 100644 --- a/app/Models/PaymentError.php +++ b/app/Models/PaymentError.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class PaymentError extends BaseModel { protected $table = 'payment_error'; @@ -24,12 +26,12 @@ class PaymentError extends BaseModel ]; protected $casts = [ - 'payment_id' => 'integer', - 'invoice_id' => 'integer', - 'parent_id' => 'integer', - 'wrong_paid_amount' => 'decimal:2', // adjust precision if needed - 'logged_by' => 'integer', - 'logged_at' => 'datetime', + 'payment_id' => 'integer', + 'invoice_id' => 'integer', + 'parent_id' => 'integer', + 'wrong_paid_amount' => 'decimal:2', // adjust precision if needed + 'logged_by' => 'integer', + 'logged_at' => 'datetime', ]; /* Optional relationships */ @@ -47,4 +49,4 @@ class PaymentError extends BaseModel { return $this->belongsTo(User::class, 'logged_by'); } -} +} \ No newline at end of file diff --git a/app/Models/PaymentInstallmentAllocation.php b/app/Models/PaymentInstallmentAllocation.php index 921913eb..2ea9896c 100644 --- a/app/Models/PaymentInstallmentAllocation.php +++ b/app/Models/PaymentInstallmentAllocation.php @@ -5,6 +5,5 @@ namespace App\Models; class PaymentInstallmentAllocation extends BaseModel { protected $guarded = []; - protected $table = 'payment_installment_allocations'; } diff --git a/app/Models/PaymentNotificationLog.php b/app/Models/PaymentNotificationLog.php index c8781282..128d0738 100644 --- a/app/Models/PaymentNotificationLog.php +++ b/app/Models/PaymentNotificationLog.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class PaymentNotificationLog extends BaseModel { protected $table = 'payment_notification_logs'; @@ -29,14 +31,14 @@ class PaymentNotificationLog extends BaseModel ]; protected $casts = [ - 'parent_id' => 'integer', - 'invoice_id' => 'integer', - 'period_year' => 'integer', - 'period_month' => 'integer', - 'head_fa_notified' => 'boolean', - 'balance_snapshot' => 'decimal:2', // adjust precision if needed - 'created_at' => 'datetime', - 'sent_at' => 'datetime', + 'parent_id' => 'integer', + 'invoice_id' => 'integer', + 'period_year' => 'integer', + 'period_month' => 'integer', + 'head_fa_notified' => 'boolean', + 'balance_snapshot' => 'decimal:2', // adjust precision if needed + 'created_at' => 'datetime', + 'sent_at' => 'datetime', ]; /* Optional relationships */ @@ -71,16 +73,16 @@ class PaymentNotificationLog extends BaseModel { $q = static::query()->orderByDesc('sent_at'); - if (! empty($from)) { + if (!empty($from)) { $q->where('sent_at', '>=', $from); } - if (! empty($to)) { + if (!empty($to)) { $q->where('sent_at', '<=', $to); } - if (! empty($type)) { + if (!empty($type)) { $q->where('type', $type); } return $q->get()->toArray(); } -} +} \ No newline at end of file diff --git a/app/Models/PaymentTransaction.php b/app/Models/PaymentTransaction.php index a765d81e..506323b2 100644 --- a/app/Models/PaymentTransaction.php +++ b/app/Models/PaymentTransaction.php @@ -2,6 +2,9 @@ namespace App\Models; +use App\Models\BaseModel; +use Illuminate\Support\Facades\DB; + class PaymentTransaction extends BaseModel { protected $table = 'payment_transactions'; @@ -26,11 +29,11 @@ class PaymentTransaction extends BaseModel ]; protected $casts = [ - 'payment_id' => 'integer', - 'amount' => 'decimal:2', // adjust precision if needed - 'transaction_fee' => 'decimal:2', // adjust precision if needed - 'transaction_date' => 'datetime', - 'is_full_payment' => 'boolean', + 'payment_id' => 'integer', + 'amount' => 'decimal:2', // adjust precision if needed + 'transaction_fee' => 'decimal:2', // adjust precision if needed + 'transaction_date' => 'datetime', + 'is_full_payment' => 'boolean', ]; /* Optional relationship */ diff --git a/app/Models/PaypalTransaction.php b/app/Models/PaypalTransaction.php index 375f6de5..1e4b2138 100644 --- a/app/Models/PaypalTransaction.php +++ b/app/Models/PaypalTransaction.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class PaypalTransaction extends BaseModel { protected $table = 'paypal_transactions'; @@ -27,11 +29,11 @@ class PaypalTransaction extends BaseModel ]; protected $casts = [ - 'payment_id' => 'integer', - 'amount' => 'decimal:2', // adjust precision if needed - 'transaction_fee' => 'decimal:2', // adjust precision if needed + 'payment_id' => 'integer', + 'amount' => 'decimal:2', // adjust precision if needed + 'transaction_fee' => 'decimal:2', // adjust precision if needed // raw_data is often JSON; if it's JSON in DB, cast to array - 'raw_data' => 'array', + 'raw_data' => 'array', ]; /* Optional relationship */ @@ -39,4 +41,4 @@ class PaypalTransaction extends BaseModel { return $this->belongsTo(Payment::class, 'payment_id'); } -} +} \ No newline at end of file diff --git a/app/Models/Permission.php b/app/Models/Permission.php index c92367ea..51c6ff03 100644 --- a/app/Models/Permission.php +++ b/app/Models/Permission.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; @@ -31,7 +32,7 @@ class Permission extends BaseModel try { return static::query()->get(); } catch (\Throwable $e) { - Log::error('Error fetching permissions: '.$e->getMessage()); + Log::error('Error fetching permissions: ' . $e->getMessage()); throw $e; } } @@ -52,12 +53,12 @@ class Permission extends BaseModel ->map(fn ($r) => (array) $r) ->all(); - Log::info('Role permissions fetched: '.print_r($rows, true)); + Log::info('Role permissions fetched: ' . print_r($rows, true)); return $rows; } catch (\Throwable $e) { - Log::error("Error fetching role permissions for role ID {$roleId}: ".$e->getMessage()); + Log::error("Error fetching role permissions for role ID {$roleId}: " . $e->getMessage()); throw $e; } } -} +} \ No newline at end of file diff --git a/app/Models/PlacementBatch.php b/app/Models/PlacementBatch.php index 1fd0855c..1cdc517c 100644 --- a/app/Models/PlacementBatch.php +++ b/app/Models/PlacementBatch.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class PlacementBatch extends BaseModel { protected $table = 'placement_batches'; @@ -33,4 +35,4 @@ class PlacementBatch extends BaseModel { return $this->belongsTo(User::class, 'updated_by'); } -} +} \ No newline at end of file diff --git a/app/Models/PlacementLevel.php b/app/Models/PlacementLevel.php index a1b251bd..17155cec 100644 --- a/app/Models/PlacementLevel.php +++ b/app/Models/PlacementLevel.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class PlacementLevel extends BaseModel { protected $table = 'placement_levels'; @@ -40,4 +42,4 @@ class PlacementLevel extends BaseModel { return $this->belongsTo(User::class, 'updated_by'); } -} +} \ No newline at end of file diff --git a/app/Models/PlacementScore.php b/app/Models/PlacementScore.php index 0cb61c10..21f41b3f 100644 --- a/app/Models/PlacementScore.php +++ b/app/Models/PlacementScore.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class PlacementScore extends BaseModel { protected $table = 'placement_scores'; @@ -20,9 +22,9 @@ class PlacementScore extends BaseModel ]; protected $casts = [ - 'batch_id' => 'integer', + 'batch_id' => 'integer', 'student_id' => 'integer', - 'score' => 'decimal:2', // change to 'integer' if score is whole number + 'score' => 'decimal:2', // change to 'integer' if score is whole number 'created_by' => 'integer', 'updated_by' => 'integer', ]; @@ -47,4 +49,4 @@ class PlacementScore extends BaseModel { return $this->belongsTo(User::class, 'updated_by'); } -} +} \ No newline at end of file diff --git a/app/Models/Preferences.php b/app/Models/Preferences.php index e0434c00..4b202b82 100644 --- a/app/Models/Preferences.php +++ b/app/Models/Preferences.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class Preferences extends BaseModel { protected $table = 'user_preferences'; @@ -32,15 +34,15 @@ class Preferences extends BaseModel ]; protected $casts = [ - 'user_id' => 'integer', + 'user_id' => 'integer', 'receive_email_notifications' => 'boolean', - 'receive_sms_notifications' => 'boolean', - 'receive_push_notifications' => 'boolean', - 'daily_summary_email' => 'boolean', - 'privacy_mode' => 'boolean', - 'marketing_emails' => 'boolean', - 'account_activity_alerts' => 'boolean', + 'receive_sms_notifications' => 'boolean', + 'receive_push_notifications' => 'boolean', + 'daily_summary_email' => 'boolean', + 'privacy_mode' => 'boolean', + 'marketing_emails' => 'boolean', + 'account_activity_alerts' => 'boolean', ]; /* Optional relationship */ diff --git a/app/Models/PrintRequest.php b/app/Models/PrintRequest.php index afddbdca..ef860363 100644 --- a/app/Models/PrintRequest.php +++ b/app/Models/PrintRequest.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class PrintRequest extends BaseModel { protected $table = 'print_requests'; @@ -22,11 +24,11 @@ class PrintRequest extends BaseModel ]; protected $casts = [ - 'teacher_id' => 'integer', - 'admin_id' => 'integer', - 'class_id' => 'integer', - 'num_copies' => 'integer', - 'required_by' => 'datetime', // if stored as DATETIME + 'teacher_id' => 'integer', + 'admin_id' => 'integer', + 'class_id' => 'integer', + 'num_copies' => 'integer', + 'required_by' => 'datetime', // if stored as DATETIME ]; /* Optional relationships */ @@ -44,4 +46,4 @@ class PrintRequest extends BaseModel { return $this->belongsTo(SchoolClass::class, 'class_id'); } -} +} \ No newline at end of file diff --git a/app/Models/Project.php b/app/Models/Project.php index c0e57a25..7041a6bb 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Project extends BaseModel @@ -44,17 +45,17 @@ class Project extends BaseModel * Helpful casts (adjust types if your DB columns differ). */ protected $casts = [ - 'student_id' => 'integer', - 'school_id' => 'integer', - 'class_section_id' => 'integer', - 'updated_by' => 'integer', - 'project_index' => 'integer', - 'score' => 'decimal:2', - 'max_points' => 'decimal:2', - 'locked_by' => 'integer', - 'locked_at' => 'datetime', // or 'float' if you prefer - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'student_id' => 'integer', + 'school_id' => 'integer', + 'class_section_id' => 'integer', + 'updated_by' => 'integer', + 'project_index' => 'integer', + 'score' => 'decimal:2', + 'max_points' => 'decimal:2', + 'locked_by' => 'integer', + 'locked_at' => 'datetime', // or 'float' if you prefer + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -90,7 +91,7 @@ class Project extends BaseModel public function scopeForTerm(Builder $q, string $semester, string $schoolYear): Builder { return $q->where('semester', $semester) - ->where('school_year', $schoolYear); + ->where('school_year', $schoolYear); } public function scopeForClassSection(Builder $q, ?int $classSectionId): Builder @@ -160,4 +161,4 @@ class Project extends BaseModel // Safe default if you're unsure. Set to false if score is numeric. return true; } -} +} \ No newline at end of file diff --git a/app/Models/PromotionAuditLog.php b/app/Models/PromotionAuditLog.php index f16d4bfa..7d6b1423 100644 --- a/app/Models/PromotionAuditLog.php +++ b/app/Models/PromotionAuditLog.php @@ -16,27 +16,16 @@ class PromotionAuditLog extends BaseModel public $timestamps = true; public const ACTION_RECORD_CREATED = 'record_created'; - public const ACTION_STATUS_CHANGED = 'status_changed'; - public const ACTION_ELIGIBILITY_EVALUATED = 'eligibility_evaluated'; - public const ACTION_PARENT_NOTIFIED = 'parent_notified'; - public const ACTION_ENROLLMENT_STARTED = 'enrollment_started'; - public const ACTION_ENROLLMENT_STEP_COMPLETED = 'enrollment_step_completed'; - public const ACTION_ENROLLMENT_COMPLETED = 'enrollment_completed'; - public const ACTION_PROMOTION_FINALIZED = 'promotion_finalized'; - public const ACTION_DEADLINE_SET = 'deadline_set'; - public const ACTION_REMINDER_SENT = 'reminder_sent'; - public const ACTION_DEADLINE_EXPIRED = 'deadline_expired'; - public const ACTION_MANUAL_OVERRIDE = 'manual_override'; protected $fillable = [ diff --git a/app/Models/PromotionQueue.php b/app/Models/PromotionQueue.php index c913d34e..578799ee 100644 --- a/app/Models/PromotionQueue.php +++ b/app/Models/PromotionQueue.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class PromotionQueue extends BaseModel @@ -21,17 +22,16 @@ class PromotionQueue extends BaseModel 'updated_at', 'updated_by', ]; - public $timestamps = true; protected $casts = [ - 'student_id' => 'integer', - 'from_class_section_id' => 'integer', - 'to_class_id' => 'integer', - 'to_class_section_id' => 'integer', - 'updated_by' => 'integer', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'student_id' => 'integer', + 'from_class_section_id' => 'integer', + 'to_class_id' => 'integer', + 'to_class_section_id' => 'integer', + 'updated_by' => 'integer', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -92,9 +92,9 @@ class PromotionQueue extends BaseModel public static function upsertQueue(array $data): ?self { $studentId = isset($data['student_id']) ? (int) $data['student_id'] : null; - $yearTo = isset($data['school_year_to']) ? (string) $data['school_year_to'] : null; + $yearTo = isset($data['school_year_to']) ? (string) $data['school_year_to'] : null; - if (! $studentId || ! $yearTo) { + if (!$studentId || !$yearTo) { return null; } @@ -114,4 +114,4 @@ class PromotionQueue extends BaseModel { return (bool) static::upsertQueue($data); } -} +} \ No newline at end of file diff --git a/app/Models/PromotionReminderLog.php b/app/Models/PromotionReminderLog.php index cbfd0c58..88973cf1 100644 --- a/app/Models/PromotionReminderLog.php +++ b/app/Models/PromotionReminderLog.php @@ -16,13 +16,9 @@ class PromotionReminderLog extends BaseModel public $timestamps = true; public const TYPE_FIRST = 'first'; - public const TYPE_HALFWAY = 'halfway'; - public const TYPE_FINAL = 'final'; - public const TYPE_EXPIRATION = 'expiration'; - public const TYPE_MANUAL = 'manual'; public const ALLOWED_TYPES = [ diff --git a/app/Models/PurchaseOrder.php b/app/Models/PurchaseOrder.php index ef898059..fbca9813 100644 --- a/app/Models/PurchaseOrder.php +++ b/app/Models/PurchaseOrder.php @@ -3,9 +3,10 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Database\Eloquent\SoftDeletes; class PurchaseOrder extends BaseModel { @@ -24,19 +25,18 @@ class PurchaseOrder extends BaseModel 'total', 'notes', ]; - public $timestamps = true; protected $casts = [ - 'supplier_id' => 'integer', - 'order_date' => 'date', // or 'datetime' if your DB stores time too - 'expected_date' => 'date', - 'subtotal' => 'decimal:2', - 'tax' => 'decimal:2', - 'total' => 'decimal:2', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', - 'deleted_at' => 'datetime', + 'supplier_id' => 'integer', + 'order_date' => 'date', // or 'datetime' if your DB stores time too + 'expected_date' => 'date', + 'subtotal' => 'decimal:2', + 'tax' => 'decimal:2', + 'total' => 'decimal:2', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + 'deleted_at' => 'datetime', ]; public function getFillable(): array @@ -49,12 +49,9 @@ class PurchaseOrder extends BaseModel * ============================================================ */ - public const STATUS_DRAFT = 'draft'; - - public const STATUS_ORDERED = 'ordered'; - + public const STATUS_DRAFT = 'draft'; + public const STATUS_ORDERED = 'ordered'; public const STATUS_RECEIVED = 'received'; - public const STATUS_CANCELED = 'canceled'; public static function allowedStatuses(): array @@ -119,8 +116,8 @@ class PurchaseOrder extends BaseModel $total = $subtotal + $tax; $this->subtotal = $subtotal; - $this->tax = $tax; - $this->total = $total; + $this->tax = $tax; + $this->total = $total; return $this; } @@ -128,21 +125,18 @@ class PurchaseOrder extends BaseModel public function markOrdered(): self { $this->status = self::STATUS_ORDERED; - return $this; } public function markReceived(): self { $this->status = self::STATUS_RECEIVED; - return $this; } public function markCanceled(): self { $this->status = self::STATUS_CANCELED; - return $this; } @@ -155,16 +149,16 @@ class PurchaseOrder extends BaseModel { // Mirrors legacy: unique purchase_orders.po_number except current id. return [ - 'po_number' => ['required', 'string', 'max:60', 'unique:purchase_orders,po_number,'.($id ?? 'NULL').',id'], + 'po_number' => ['required', 'string', 'max:60', 'unique:purchase_orders,po_number,' . ($id ?? 'NULL') . ',id'], 'supplier_id' => ['required', 'integer', 'min:1', 'exists:suppliers,id'], - 'status' => ['nullable', 'string', 'in:'.implode(',', self::allowedStatuses())], + 'status' => ['nullable', 'string', 'in:' . implode(',', self::allowedStatuses())], - 'order_date' => ['nullable', 'date'], - 'expected_date' => ['nullable', 'date', 'after_or_equal:order_date'], - 'subtotal' => ['nullable', 'numeric', 'min:0'], - 'tax' => ['nullable', 'numeric', 'min:0'], - 'total' => ['nullable', 'numeric', 'min:0'], - 'notes' => ['nullable', 'string', 'max:5000'], + 'order_date' => ['nullable', 'date'], + 'expected_date' => ['nullable', 'date', 'after_or_equal:order_date'], + 'subtotal' => ['nullable', 'numeric', 'min:0'], + 'tax' => ['nullable', 'numeric', 'min:0'], + 'total' => ['nullable', 'numeric', 'min:0'], + 'notes' => ['nullable', 'string', 'max:5000'], ]; } } diff --git a/app/Models/PurchaseOrderItem.php b/app/Models/PurchaseOrderItem.php index 2ef53bd9..ba44d165 100644 --- a/app/Models/PurchaseOrderItem.php +++ b/app/Models/PurchaseOrderItem.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class PurchaseOrderItem extends BaseModel @@ -16,17 +17,16 @@ class PurchaseOrderItem extends BaseModel 'received_qty', 'unit_cost', ]; - public $timestamps = true; protected $casts = [ 'purchase_order_id' => 'integer', - 'supply_id' => 'integer', - 'quantity' => 'integer', - 'received_qty' => 'integer', - 'unit_cost' => 'decimal:2', // adjust scale to match DB (e.g., decimal:4) - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'supply_id' => 'integer', + 'quantity' => 'integer', + 'received_qty' => 'integer', + 'unit_cost' => 'decimal:2', // adjust scale to match DB (e.g., decimal:4) + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; public function getFillable(): array @@ -57,18 +57,16 @@ class PurchaseOrderItem extends BaseModel // total ordered cost public function getLineTotalAttribute(): float { - $qty = (int) ($this->quantity ?? 0); + $qty = (int) ($this->quantity ?? 0); $cost = (float) ($this->unit_cost ?? 0); - return $qty * $cost; } // total received cost public function getReceivedLineTotalAttribute(): float { - $qty = (int) ($this->received_qty ?? 0); + $qty = (int) ($this->received_qty ?? 0); $cost = (float) ($this->unit_cost ?? 0); - return $qty * $cost; } @@ -83,11 +81,11 @@ class PurchaseOrderItem extends BaseModel // keep strict by default to match legacy behavior return [ 'purchase_order_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:purchase_orders,id'], - 'supply_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:supplies,id'], - 'description' => ['nullable', 'string', 'max:1000'], - 'quantity' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1'], - 'received_qty' => ['nullable', 'integer', 'min:0', 'lte:quantity'], - 'unit_cost' => [$updating ? 'sometimes' : 'required', 'numeric', 'min:0'], + 'supply_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:supplies,id'], + 'description' => ['nullable', 'string', 'max:1000'], + 'quantity' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1'], + 'received_qty' => ['nullable', 'integer', 'min:0', 'lte:quantity'], + 'unit_cost' => [$updating ? 'sometimes' : 'required', 'numeric', 'min:0'], ]; } } diff --git a/app/Models/Quiz.php b/app/Models/Quiz.php index c131eb4c..6663fd33 100644 --- a/app/Models/Quiz.php +++ b/app/Models/Quiz.php @@ -2,12 +2,12 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Quiz extends BaseModel { protected $table = 'quiz'; - public $timestamps = false; protected $fillable = [ @@ -30,17 +30,17 @@ class Quiz extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', - 'school_id' => 'integer', + 'student_id' => 'integer', + 'school_id' => 'integer', 'class_section_id' => 'integer', - 'updated_by' => 'integer', - 'quiz_index' => 'integer', - 'score' => 'decimal:2', - 'max_points' => 'decimal:2', - 'locked_by' => 'integer', - 'locked_at' => 'datetime', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'updated_by' => 'integer', + 'quiz_index' => 'integer', + 'score' => 'decimal:2', + 'max_points' => 'decimal:2', + 'locked_by' => 'integer', + 'locked_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; public function student(): BelongsTo diff --git a/app/Models/Refund.php b/app/Models/Refund.php index 536b5010..0755eebe 100644 --- a/app/Models/Refund.php +++ b/app/Models/Refund.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Refund extends BaseModel @@ -30,24 +31,23 @@ class Refund extends BaseModel 'check_nbr', 'check_file', ]; - public $timestamps = true; protected $casts = [ - 'parent_id' => 'integer', - 'invoice_id' => 'integer', - 'approved_by' => 'integer', - 'updated_by' => 'integer', + 'parent_id' => 'integer', + 'invoice_id' => 'integer', + 'approved_by' => 'integer', + 'updated_by' => 'integer', - 'refund_amount' => 'decimal:2', + 'refund_amount' => 'decimal:2', 'refund_paid_amount' => 'decimal:2', - 'requested_at' => 'datetime', - 'approved_at' => 'datetime', - 'refunded_at' => 'datetime', + 'requested_at' => 'datetime', + 'approved_at' => 'datetime', + 'refunded_at' => 'datetime', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -56,15 +56,10 @@ class Refund extends BaseModel */ public const STATUS_PENDING = 'Pending'; - public const STATUS_APPROVED = 'Approved'; - public const STATUS_PARTIAL = 'Partial'; - public const STATUS_PAID = 'Paid'; - public const STATUS_REJECTED = 'Rejected'; - public const STATUS_CANCELED = 'Canceled'; public static function paidOutStatuses(): array @@ -144,18 +139,18 @@ class Refund extends BaseModel public static function rules(?int $id = null): array { return [ - 'parent_id' => ['required', 'integer', 'min:1', 'exists:parents,id'], // adjust table name - 'school_year' => ['required', 'string', 'max:20'], - 'invoice_id' => ['nullable', 'integer', 'exists:invoices,id'], + 'parent_id' => ['required', 'integer', 'min:1', 'exists:parents,id'], // adjust table name + 'school_year' => ['required', 'string', 'max:20'], + 'invoice_id' => ['nullable', 'integer', 'exists:invoices,id'], - 'refund_amount' => ['required', 'numeric', 'min:0'], + 'refund_amount' => ['required', 'numeric', 'min:0'], 'refund_paid_amount' => ['nullable', 'numeric', 'min:0'], - 'requested_at' => ['nullable', 'date'], - 'approved_at' => ['nullable', 'date', 'after_or_equal:requested_at'], - 'refunded_at' => ['nullable', 'date', 'after_or_equal:approved_at'], + 'requested_at' => ['nullable', 'date'], + 'approved_at' => ['nullable', 'date', 'after_or_equal:requested_at'], + 'refunded_at' => ['nullable', 'date', 'after_or_equal:approved_at'], - 'status' => ['required', 'string', 'in:'.implode(',', [ + 'status' => ['required', 'string', 'in:' . implode(',', [ self::STATUS_PENDING, self::STATUS_APPROVED, self::STATUS_PARTIAL, @@ -164,17 +159,17 @@ class Refund extends BaseModel self::STATUS_CANCELED, ])], - 'reason' => ['nullable', 'string', 'max:2000'], - 'request' => ['nullable', 'string'], - 'note' => ['nullable', 'string', 'max:5000'], - 'semester' => ['nullable', 'string', 'max:20'], + 'reason' => ['nullable', 'string', 'max:2000'], + 'request' => ['nullable', 'string'], + 'note' => ['nullable', 'string', 'max:5000'], + 'semester' => ['nullable', 'string', 'max:20'], - 'approved_by' => ['nullable', 'integer'], - 'updated_by' => ['nullable', 'integer'], + 'approved_by' => ['nullable', 'integer'], + 'updated_by' => ['nullable', 'integer'], 'refund_method' => ['nullable', 'string', 'max:50'], // cash/check/cc/etc. - 'check_nbr' => ['nullable', 'string', 'max:80'], - 'check_file' => ['nullable', 'string', 'max:255'], + 'check_nbr' => ['nullable', 'string', 'max:80'], + 'check_file' => ['nullable', 'string', 'max:255'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/Reimbursement.php b/app/Models/Reimbursement.php index 14a07d73..d69e6a5c 100644 --- a/app/Models/Reimbursement.php +++ b/app/Models/Reimbursement.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Reimbursement extends BaseModel @@ -32,13 +33,13 @@ class Reimbursement extends BaseModel public $timestamps = true; protected $casts = [ - 'amount' => 'decimal:2', - 'expense_id' => 'integer', - 'approved_by' => 'integer', - 'added_by' => 'integer', - 'batch_number' => 'integer', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'amount' => 'decimal:2', + 'expense_id' => 'integer', + 'approved_by' => 'integer', + 'added_by' => 'integer', + 'batch_number' => 'integer', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -46,15 +47,11 @@ class Reimbursement extends BaseModel * ============================================================ */ - public const STATUS_DRAFT = 'draft'; - - public const STATUS_PENDING = 'pending'; - - public const STATUS_APPROVED = 'approved'; - + public const STATUS_DRAFT = 'draft'; + public const STATUS_PENDING = 'pending'; + public const STATUS_APPROVED = 'approved'; public const STATUS_REIMBURSED = 'reimbursed'; - - public const STATUS_REJECTED = 'rejected'; + public const STATUS_REJECTED = 'rejected'; public static function allowedStatuses(): array { @@ -152,22 +149,22 @@ class Reimbursement extends BaseModel public static function rules(bool $updating = false): array { return [ - 'amount' => [$updating ? 'sometimes' : 'required', 'numeric', 'min:0'], - 'reimbursed_to' => ['nullable', 'string', 'max:255'], - 'expense_id' => ['nullable', 'integer', 'exists:expenses,id'], - 'description' => ['nullable', 'string', 'max:5000'], - 'status' => ['nullable', 'string', 'in:'.implode(',', self::allowedStatuses())], - 'receipt_path' => ['nullable', 'string', 'max:255'], + 'amount' => [$updating ? 'sometimes' : 'required', 'numeric', 'min:0'], + 'reimbursed_to' => ['nullable', 'string', 'max:255'], + 'expense_id' => ['nullable', 'integer', 'exists:expenses,id'], + 'description' => ['nullable', 'string', 'max:5000'], + 'status' => ['nullable', 'string', 'in:' . implode(',', self::allowedStatuses())], + 'receipt_path' => ['nullable', 'string', 'max:255'], - 'approved_by' => ['nullable', 'integer'], - 'added_by' => ['nullable', 'integer'], + 'approved_by' => ['nullable', 'integer'], + 'added_by' => ['nullable', 'integer'], - 'school_year' => ['nullable', 'string', 'max:20'], - 'semester' => ['nullable', 'string', 'max:20'], + 'school_year' => ['nullable', 'string', 'max:20'], + 'semester' => ['nullable', 'string', 'max:20'], - 'check_number' => ['nullable', 'string', 'max:80'], + 'check_number' => ['nullable', 'string', 'max:80'], 'reimbursement_method' => ['nullable', 'string', 'max:50'], - 'batch_number' => ['nullable', 'integer', 'min:1'], + 'batch_number' => ['nullable', 'integer', 'min:1'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/ReimbursementBatch.php b/app/Models/ReimbursementBatch.php index 8f866a52..02796a29 100644 --- a/app/Models/ReimbursementBatch.php +++ b/app/Models/ReimbursementBatch.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -29,11 +30,11 @@ class ReimbursementBatch extends BaseModel ]; protected $casts = [ - 'created_by' => 'integer', - 'closed_by' => 'integer', + 'created_by' => 'integer', + 'closed_by' => 'integer', 'yearly_batch_number' => 'integer', - 'opened_at' => 'datetime', - 'closed_at' => 'datetime', + 'opened_at' => 'datetime', + 'closed_at' => 'datetime', ]; /* ============================================================ @@ -41,11 +42,9 @@ class ReimbursementBatch extends BaseModel * ============================================================ */ - public const STATUS_OPEN = 'open'; - + public const STATUS_OPEN = 'open'; public const STATUS_CLOSED = 'closed'; - - public const STATUS_DRAFT = 'draft'; + public const STATUS_DRAFT = 'draft'; public static function allowedStatuses(): array { @@ -156,16 +155,16 @@ class ReimbursementBatch extends BaseModel public static function rules(?int $id = null): array { return [ - 'title' => ['required', 'string', 'max:255'], - 'status' => ['required', 'string', 'in:'.implode(',', self::allowedStatuses())], - 'created_by' => ['nullable', 'integer'], - 'closed_by' => ['nullable', 'integer'], - 'opened_at' => ['nullable', 'date'], - 'closed_at' => ['nullable', 'date', 'after_or_equal:opened_at'], - 'notes' => ['nullable', 'string', 'max:5000'], - 'school_year' => ['nullable', 'string', 'max:20'], - 'semester' => ['nullable', 'string', 'max:20'], + 'title' => ['required', 'string', 'max:255'], + 'status' => ['required', 'string', 'in:' . implode(',', self::allowedStatuses())], + 'created_by' => ['nullable', 'integer'], + 'closed_by' => ['nullable', 'integer'], + 'opened_at' => ['nullable', 'date'], + 'closed_at' => ['nullable', 'date', 'after_or_equal:opened_at'], + 'notes' => ['nullable', 'string', 'max:5000'], + 'school_year' => ['nullable', 'string', 'max:20'], + 'semester' => ['nullable', 'string', 'max:20'], 'yearly_batch_number' => ['nullable', 'integer', 'min:1'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/ReimbursementBatchAdminFile.php b/app/Models/ReimbursementBatchAdminFile.php index 757fe6d2..f385d95d 100644 --- a/app/Models/ReimbursementBatchAdminFile.php +++ b/app/Models/ReimbursementBatchAdminFile.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class ReimbursementBatchAdminFile extends BaseModel @@ -23,10 +24,10 @@ class ReimbursementBatchAdminFile extends BaseModel ]; protected $casts = [ - 'batch_id' => 'integer', - 'admin_id' => 'integer', - 'uploaded_by' => 'integer', - 'uploaded_at' => 'datetime', + 'batch_id' => 'integer', + 'admin_id' => 'integer', + 'uploaded_by' => 'integer', + 'uploaded_at' => 'datetime', ]; /* ============================================================ @@ -74,12 +75,12 @@ class ReimbursementBatchAdminFile extends BaseModel public static function rules(bool $updating = false): array { return [ - 'batch_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:reimbursement_batches,id'], - 'admin_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:admins,id'], // adjust table - 'filename' => [$updating ? 'sometimes' : 'required', 'string', 'max:255'], - 'original_filename' => ['nullable', 'string', 'max:255'], - 'uploaded_at' => ['nullable', 'date'], - 'uploaded_by' => ['nullable', 'integer'], + 'batch_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:reimbursement_batches,id'], + 'admin_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:admins,id'], // adjust table + 'filename' => [$updating ? 'sometimes' : 'required', 'string', 'max:255'], + 'original_filename' => ['nullable', 'string', 'max:255'], + 'uploaded_at' => ['nullable', 'date'], + 'uploaded_by' => ['nullable', 'integer'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/ReimbursementBatchItem.php b/app/Models/ReimbursementBatchItem.php index d10a80b3..daff3c56 100644 --- a/app/Models/ReimbursementBatchItem.php +++ b/app/Models/ReimbursementBatchItem.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class ReimbursementBatchItem extends BaseModel @@ -27,12 +28,12 @@ class ReimbursementBatchItem extends BaseModel ]; protected $casts = [ - 'batch_id' => 'integer', - 'expense_id' => 'integer', + 'batch_id' => 'integer', + 'expense_id' => 'integer', 'reimbursement_id' => 'integer', - 'admin_id' => 'integer', - 'assigned_at' => 'datetime', - 'unassigned_at' => 'datetime', + 'admin_id' => 'integer', + 'assigned_at' => 'datetime', + 'unassigned_at' => 'datetime', ]; /* ============================================================ @@ -84,14 +85,14 @@ class ReimbursementBatchItem extends BaseModel public function scopeAssigned(Builder $q): Builder { return $q->whereNotNull('admin_id') - ->whereNotNull('assigned_at') - ->whereNull('unassigned_at'); + ->whereNotNull('assigned_at') + ->whereNull('unassigned_at'); } public function scopeUnassigned(Builder $q): Builder { return $q->whereNull('admin_id') - ->whereNull('assigned_at'); + ->whereNull('assigned_at'); } /* ============================================================ @@ -136,15 +137,15 @@ class ReimbursementBatchItem extends BaseModel public static function rules(bool $updating = false): array { return [ - 'batch_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:reimbursement_batches,id'], - 'expense_id' => ['nullable', 'integer', 'exists:expenses,id'], + 'batch_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:reimbursement_batches,id'], + 'expense_id' => ['nullable', 'integer', 'exists:expenses,id'], 'reimbursement_id' => ['nullable', 'integer', 'exists:reimbursements,id'], - 'admin_id' => ['nullable', 'integer'], // add exists rule if you know the table - 'assigned_at' => ['nullable', 'date'], - 'unassigned_at' => ['nullable', 'date', 'after_or_equal:assigned_at'], - 'notes' => ['nullable', 'string', 'max:5000'], - 'school_year' => ['nullable', 'string', 'max:20'], - 'semester' => ['nullable', 'string', 'max:20'], + 'admin_id' => ['nullable', 'integer'], // add exists rule if you know the table + 'assigned_at' => ['nullable', 'date'], + 'unassigned_at' => ['nullable', 'date', 'after_or_equal:assigned_at'], + 'notes' => ['nullable', 'string', 'max:5000'], + 'school_year' => ['nullable', 'string', 'max:20'], + 'semester' => ['nullable', 'string', 'max:20'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/ReportCardAcknowledgement.php b/app/Models/ReportCardAcknowledgement.php index 0755198c..d7f3ad90 100644 --- a/app/Models/ReportCardAcknowledgement.php +++ b/app/Models/ReportCardAcknowledgement.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class ReportCardAcknowledgement extends BaseModel @@ -21,16 +22,15 @@ class ReportCardAcknowledgement extends BaseModel 'created_at', 'updated_at', ]; - public $timestamps = true; protected $casts = [ - 'parent_id' => 'integer', - 'student_id' => 'integer', - 'viewed_at' => 'datetime', - 'signed_at' => 'datetime', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'parent_id' => 'integer', + 'student_id' => 'integer', + 'viewed_at' => 'datetime', + 'signed_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -67,7 +67,7 @@ class ReportCardAcknowledgement extends BaseModel public function scopeForTerm(Builder $q, string $schoolYear, string $semester): Builder { return $q->where('school_year', $schoolYear) - ->where('semester', $semester); + ->where('semester', $semester); } public function scopeSigned(Builder $q): Builder @@ -137,15 +137,15 @@ class ReportCardAcknowledgement extends BaseModel public static function rules(bool $updating = false): array { return [ - 'parent_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1'], - 'student_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1'], - 'school_year' => [$updating ? 'sometimes' : 'required', 'string', 'max:20'], - 'semester' => [$updating ? 'sometimes' : 'required', 'string', 'max:20'], + 'parent_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1'], + 'student_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1'], + 'school_year' => [$updating ? 'sometimes' : 'required', 'string', 'max:20'], + 'semester' => [$updating ? 'sometimes' : 'required', 'string', 'max:20'], - 'viewed_at' => ['nullable', 'date'], - 'signed_at' => ['nullable', 'date', 'after_or_equal:viewed_at'], - 'signed_name' => ['nullable', 'string', 'max:255'], - 'signer_ip' => ['nullable', 'string', 'max:45'], // IPv4/IPv6 + 'viewed_at' => ['nullable', 'date'], + 'signed_at' => ['nullable', 'date', 'after_or_equal:viewed_at'], + 'signed_name' => ['nullable', 'string', 'max:255'], + 'signer_ip' => ['nullable', 'string', 'max:45'], // IPv4/IPv6 ]; } -} +} \ No newline at end of file diff --git a/app/Models/Role.php b/app/Models/Role.php index e129b82e..979b0cc3 100644 --- a/app/Models/Role.php +++ b/app/Models/Role.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; class Role extends BaseModel { @@ -18,12 +19,11 @@ class Role extends BaseModel 'created_at', 'updated_at', ]; - public $timestamps = true; protected $casts = [ - 'priority' => 'integer', - 'is_active' => 'boolean', + 'priority' => 'integer', + 'is_active' => 'boolean', 'created_at' => 'datetime', 'updated_at' => 'datetime', ]; @@ -52,47 +52,43 @@ class Role extends BaseModel * Find roles by names or slugs (case-insensitive), active only, ordered by priority ASC. */ - // Put these INSIDE the Role model, replacing the current implementations +// Put these INSIDE the Role model, replacing the current implementations - public static function findByNamesOrSlugs(array $keys): array - { - $keys = array_values(array_filter(array_map('strval', $keys))); - if (empty($keys)) { - return []; - } +public static function findByNamesOrSlugs(array $keys): array +{ + $keys = array_values(array_filter(array_map('strval', $keys))); + if (empty($keys)) return []; - $lower = array_map('mb_strtolower', $keys); - $placeholders = implode(',', array_fill(0, count($lower), '?')); + $lower = array_map('mb_strtolower', $keys); + $placeholders = implode(',', array_fill(0, count($lower), '?')); - return static::query() - ->active() - ->where(function (Builder $q) use ($lower, $placeholders) { - $q->whereRaw("LOWER(name) IN ($placeholders)", $lower) - ->orWhereRaw("LOWER(slug) IN ($placeholders)", $lower); - }) - ->orderBy('priority', 'asc') - ->get() - ->all(); - } + return static::query() + ->active() + ->where(function (Builder $q) use ($lower, $placeholders) { + $q->whereRaw("LOWER(name) IN ($placeholders)", $lower) + ->orWhereRaw("LOWER(slug) IN ($placeholders)", $lower); + }) + ->orderBy('priority', 'asc') + ->get() + ->all(); +} - public static function getIdsByNames(array $names): array - { - $names = array_values(array_filter(array_map('strval', $names))); - if (empty($names)) { - return []; - } +public static function getIdsByNames(array $names): array +{ + $names = array_values(array_filter(array_map('strval', $names))); + if (empty($names)) return []; - $lower = array_map('mb_strtolower', $names); - $placeholders = implode(',', array_fill(0, count($lower), '?')); + $lower = array_map('mb_strtolower', $names); + $placeholders = implode(',', array_fill(0, count($lower), '?')); - $ids = static::query() - ->select('id') - ->whereRaw("LOWER(name) IN ($placeholders)", $lower) - ->pluck('id') - ->all(); + $ids = static::query() + ->select('id') + ->whereRaw("LOWER(name) IN ($placeholders)", $lower) + ->pluck('id') + ->all(); - return array_map('intval', $ids); - } + return array_map('intval', $ids); +} /** * Get dashboard_route by name or slug (case-insensitive), active only. @@ -100,9 +96,7 @@ class Role extends BaseModel public static function getRouteByNameOrSlug(string $key): ?string { $key = trim((string) $key); - if ($key === '') { - return null; - } + if ($key === '') return null; $lower = mb_strtolower($key); @@ -110,7 +104,7 @@ class Role extends BaseModel ->active() ->where(function (Builder $q) use ($lower) { $q->whereRaw('LOWER(name) = ?', [$lower]) - ->orWhereRaw('LOWER(slug) = ?', [$lower]); + ->orWhereRaw('LOWER(slug) = ?', [$lower]); }) ->first(); @@ -147,12 +141,12 @@ class Role extends BaseModel public static function rules(?int $id = null): array { return [ - 'name' => ['required', 'string', 'max:255'], - 'slug' => ['required', 'string', 'max:255', 'unique:roles,slug,'.($id ?? 'NULL').',id'], - 'description' => ['nullable', 'string', 'max:2000'], + 'name' => ['required', 'string', 'max:255'], + 'slug' => ['required', 'string', 'max:255', 'unique:roles,slug,' . ($id ?? 'NULL') . ',id'], + 'description' => ['nullable', 'string', 'max:2000'], 'dashboard_route' => ['nullable', 'string', 'max:255'], - 'priority' => ['nullable', 'integer', 'min:0'], - 'is_active' => ['nullable', 'boolean'], + 'priority' => ['nullable', 'integer', 'min:0'], + 'is_active' => ['nullable', 'boolean'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/RoleNavItem.php b/app/Models/RoleNavItem.php index 8b1968b4..41f16cff 100644 --- a/app/Models/RoleNavItem.php +++ b/app/Models/RoleNavItem.php @@ -3,12 +3,12 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class RoleNavItem extends BaseModel { protected $table = 'role_nav_items'; - public $timestamps = true; protected $fillable = [ @@ -17,10 +17,10 @@ class RoleNavItem extends BaseModel ]; protected $casts = [ - 'role_id' => 'integer', + 'role_id' => 'integer', 'nav_item_id' => 'integer', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -46,7 +46,6 @@ class RoleNavItem extends BaseModel public function scopeForRoles(Builder $q, array $roleIds): Builder { $roleIds = array_values(array_unique(array_filter(array_map('intval', $roleIds)))); - return empty($roleIds) ? $q->whereRaw('1=0') : $q->whereIn('role_id', $roleIds); } @@ -61,15 +60,11 @@ class RoleNavItem extends BaseModel public static function getNavItemIdsForRoles(array $roleNames): array { $roleNames = array_values(array_filter(array_map('strval', $roleNames))); - if (empty($roleNames)) { - return []; - } + if (empty($roleNames)) return []; // Uses the Role model you converted earlier $roleIds = Role::getIdsByNames($roleNames); - if (empty($roleIds)) { - return []; - } + if (empty($roleIds)) return []; // pluck nav_item_id, unique, sorted (optional) return static::query() @@ -90,8 +85,8 @@ class RoleNavItem extends BaseModel public static function rules(bool $updating = false): array { return [ - 'role_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:roles,id'], + 'role_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:roles,id'], 'nav_item_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:nav_items,id'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/RolePermission.php b/app/Models/RolePermission.php index 2cf521f0..b39760ab 100644 --- a/app/Models/RolePermission.php +++ b/app/Models/RolePermission.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\Log; @@ -21,19 +22,18 @@ class RolePermission extends BaseModel 'created_at', 'updated_at', ]; - public $timestamps = true; protected $casts = [ - 'role_id' => 'integer', - 'permission_id' => 'integer', - 'can_create' => 'boolean', - 'can_read' => 'boolean', - 'can_update' => 'boolean', - 'can_delete' => 'boolean', - 'can_manage' => 'boolean', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'role_id' => 'integer', + 'permission_id' => 'integer', + 'can_create' => 'boolean', + 'can_read' => 'boolean', + 'can_update' => 'boolean', + 'can_delete' => 'boolean', + 'can_manage' => 'boolean', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -117,7 +117,7 @@ class RolePermission extends BaseModel return [ 'can_create' => $manage ? true : (bool) $this->can_create, - 'can_read' => $manage ? true : (bool) $this->can_read, + 'can_read' => $manage ? true : (bool) $this->can_read, 'can_update' => $manage ? true : (bool) $this->can_update, 'can_delete' => $manage ? true : (bool) $this->can_delete, 'can_manage' => $manage, @@ -130,11 +130,10 @@ class RolePermission extends BaseModel public function setCrud(bool $create, bool $read, bool $update, bool $delete, bool $manage = false): self { $this->can_create = $create; - $this->can_read = $read; + $this->can_read = $read; $this->can_update = $update; $this->can_delete = $delete; $this->can_manage = $manage; - return $this; } @@ -146,14 +145,14 @@ class RolePermission extends BaseModel public static function rules(bool $updating = false): array { return [ - 'role_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:roles,id'], + 'role_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:roles,id'], 'permission_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1', 'exists:permissions,id'], - 'can_create' => ['nullable', 'boolean'], - 'can_read' => ['nullable', 'boolean'], - 'can_update' => ['nullable', 'boolean'], - 'can_delete' => ['nullable', 'boolean'], - 'can_manage' => ['nullable', 'boolean'], + 'can_create' => ['nullable', 'boolean'], + 'can_read' => ['nullable', 'boolean'], + 'can_update' => ['nullable', 'boolean'], + 'can_delete' => ['nullable', 'boolean'], + 'can_manage' => ['nullable', 'boolean'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/SchoolClass.php b/app/Models/SchoolClass.php index f42a4ca1..e5ee65e4 100644 --- a/app/Models/SchoolClass.php +++ b/app/Models/SchoolClass.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class SchoolClass extends BaseModel { protected $table = 'classes'; @@ -38,7 +40,6 @@ class SchoolClass extends BaseModel public static function createClass(array $data): int { $row = static::create($data); - return (int) $row->id; } @@ -50,10 +51,7 @@ class SchoolClass extends BaseModel public static function deleteClass(int $id): bool { $row = static::query()->find($id); - if (! $row) { - return false; - } - + if (!$row) return false; return (bool) $row->delete(); } -} +} \ No newline at end of file diff --git a/app/Models/SchoolYear.php b/app/Models/SchoolYear.php index 1170546f..385e4de4 100644 --- a/app/Models/SchoolYear.php +++ b/app/Models/SchoolYear.php @@ -5,11 +5,8 @@ namespace App\Models; class SchoolYear extends BaseModel { public const STATUS_DRAFT = 'draft'; - public const STATUS_ACTIVE = 'active'; - public const STATUS_CLOSED = 'closed'; - public const STATUS_ARCHIVED = 'archived'; protected $table = 'school_years'; diff --git a/app/Models/ScoreComment.php b/app/Models/ScoreComment.php index 9045017a..a4a19d12 100644 --- a/app/Models/ScoreComment.php +++ b/app/Models/ScoreComment.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class ScoreComment extends BaseModel @@ -33,14 +34,14 @@ class ScoreComment extends BaseModel ]; protected $casts = [ - 'student_id' => 'integer', + 'student_id' => 'integer', 'class_section_id' => 'integer', - 'reviewed_by' => 'integer', - 'commented_by' => 'integer', - 'created_at' => 'datetime', + 'reviewed_by' => 'integer', + 'commented_by' => 'integer', + 'created_at' => 'datetime', // If comment_review is a tinyint(1) flag in DB, boolean cast helps - 'comment_review' => 'boolean', + 'comment_review' => 'boolean', ]; /* ============================================================ @@ -88,7 +89,7 @@ class ScoreComment extends BaseModel public function scopeForTerm(Builder $q, string $schoolYear, string $semester): Builder { return $q->where('school_year', $schoolYear) - ->where('semester', $semester); + ->where('semester', $semester); } public function scopeForScoreType(Builder $q, string $scoreType): Builder @@ -101,7 +102,7 @@ class ScoreComment extends BaseModel // supports either boolean flag or reviewed_by presence return $q->where(function (Builder $w) { $w->where('comment_review', 1) - ->orWhereNotNull('reviewed_by'); + ->orWhereNotNull('reviewed_by'); }); } @@ -156,19 +157,19 @@ class ScoreComment extends BaseModel public static function rules(bool $updating = false): array { return [ - 'student_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1'], + 'student_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1'], 'class_section_id' => [$updating ? 'sometimes' : 'required', 'integer', 'min:1'], - 'score_type' => [$updating ? 'sometimes' : 'required', 'string', 'max:50'], - 'school_year' => [$updating ? 'sometimes' : 'required', 'string', 'max:20'], - 'semester' => [$updating ? 'sometimes' : 'required', 'string', 'max:20'], + 'score_type' => [$updating ? 'sometimes' : 'required', 'string', 'max:50'], + 'school_year' => [$updating ? 'sometimes' : 'required', 'string', 'max:20'], + 'semester' => [$updating ? 'sometimes' : 'required', 'string', 'max:20'], - 'comment' => ['nullable', 'string', 'max:5000'], - 'comment_review' => ['nullable', 'boolean'], - 'reviewed_by' => ['nullable', 'integer'], - 'commented_by' => ['nullable', 'integer'], + 'comment' => ['nullable', 'string', 'max:5000'], + 'comment_review' => ['nullable', 'boolean'], + 'reviewed_by' => ['nullable', 'integer'], + 'commented_by' => ['nullable', 'integer'], // created_at is DB default; allow client to omit it - 'created_at' => ['nullable', 'date'], + 'created_at' => ['nullable', 'date'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/Section.php b/app/Models/Section.php index 66992a5d..ce3a37cc 100644 --- a/app/Models/Section.php +++ b/app/Models/Section.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Section extends BaseModel @@ -16,7 +17,6 @@ class Section extends BaseModel 'updated_at', 'updated_by', ]; - public $timestamps = true; protected $casts = [ @@ -49,13 +49,11 @@ class Section extends BaseModel public function scopeSearch(Builder $q, string $term): Builder { $term = trim($term); - if ($term === '') { - return $q; - } + if ($term === '') return $q; return $q->where(function (Builder $w) use ($term) { $w->where('section_name', 'like', "%{$term}%") - ->orWhere('description', 'like', "%{$term}%"); + ->orWhere('description', 'like', "%{$term}%"); }); } @@ -80,9 +78,7 @@ class Section extends BaseModel public static function updateSection(int $sectionId, array $data): bool { $section = static::query()->find($sectionId); - if (! $section) { - return false; - } + if (!$section) return false; // Laravel will set updated_at automatically when saving return $section->fill($data)->save(); @@ -95,9 +91,7 @@ class Section extends BaseModel public static function deleteSection(int $sectionId): bool { $section = static::query()->find($sectionId); - if (! $section) { - return false; - } + if (!$section) return false; return (bool) $section->delete(); } @@ -110,9 +104,9 @@ class Section extends BaseModel public static function rules(?int $id = null): array { return [ - 'section_name' => ['required', 'string', 'max:255', 'unique:sections,section_name,'.($id ?? 'NULL').',id'], - 'description' => ['nullable', 'string', 'max:2000'], - 'updated_by' => ['nullable', 'integer'], + 'section_name' => ['required', 'string', 'max:255', 'unique:sections,section_name,' . ($id ?? 'NULL') . ',id'], + 'description' => ['nullable', 'string', 'max:2000'], + 'updated_by' => ['nullable', 'integer'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/SectionPlacementBatch.php b/app/Models/SectionPlacementBatch.php index f9c585e1..c4a22c14 100644 --- a/app/Models/SectionPlacementBatch.php +++ b/app/Models/SectionPlacementBatch.php @@ -9,11 +9,8 @@ class SectionPlacementBatch extends BaseModel protected $table = 'section_placement_batches'; public const STATUS_DRAFT = 'draft'; - public const STATUS_FINALIZED = 'finalized'; - public const STATUS_CANCELLED = 'cancelled'; - public const STATUS_SUPERSEDED = 'superseded'; protected $fillable = [ diff --git a/app/Models/SemesterScore.php b/app/Models/SemesterScore.php index f2f46aba..d232d307 100644 --- a/app/Models/SemesterScore.php +++ b/app/Models/SemesterScore.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class SemesterScore extends BaseModel @@ -38,26 +39,26 @@ class SemesterScore extends BaseModel public $timestamps = true; protected $casts = [ - 'student_id' => 'integer', - 'school_id' => 'integer', - 'class_section_id' => 'integer', - 'updated_by' => 'integer', + 'student_id' => 'integer', + 'school_id' => 'integer', + 'class_section_id' => 'integer', + 'updated_by' => 'integer', // averages/scores: keep decimal to avoid float drift - 'homework_avg' => 'decimal:2', - 'quiz_avg' => 'decimal:2', - 'project_avg' => 'decimal:2', - 'midterm_exam_score' => 'decimal:2', - 'final_exam_score' => 'decimal:2', - 'attendance_score' => 'decimal:2', + 'homework_avg' => 'decimal:2', + 'quiz_avg' => 'decimal:2', + 'project_avg' => 'decimal:2', + 'midterm_exam_score' => 'decimal:2', + 'final_exam_score' => 'decimal:2', + 'attendance_score' => 'decimal:2', 'participation_score' => 'decimal:2', - 'ptap_score' => 'decimal:2', - 'test_avg' => 'decimal:2', - 'semester_score' => 'decimal:2', - 'snapshot_id' => 'integer', + 'ptap_score' => 'decimal:2', + 'test_avg' => 'decimal:2', + 'semester_score' => 'decimal:2', + 'snapshot_id' => 'integer', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -99,7 +100,7 @@ class SemesterScore extends BaseModel public function scopeForTerm(Builder $q, string $semester, string $schoolYear): Builder { return $q->where('semester', $semester) - ->where('school_year', $schoolYear); + ->where('school_year', $schoolYear); } public function scopeForClassSection(Builder $q, ?int $classSectionId): Builder @@ -125,8 +126,8 @@ class SemesterScore extends BaseModel } $keys = [ - 'student_id' => (int) $data['student_id'], - 'semester' => (string) $data['semester'], + 'student_id' => (int) $data['student_id'], + 'semester' => (string) $data['semester'], 'school_year' => (string) $data['school_year'], ]; @@ -154,27 +155,27 @@ class SemesterScore extends BaseModel $required = $updating ? 'sometimes' : 'required'; return [ - 'student_id' => [$required, 'integer', 'min:1'], - 'semester' => [$required, 'string', 'max:20'], - 'school_year' => [$required, 'string', 'max:20'], + 'student_id' => [$required, 'integer', 'min:1'], + 'semester' => [$required, 'string', 'max:20'], + 'school_year' => [$required, 'string', 'max:20'], - 'school_id' => ['nullable', 'integer', 'min:1'], + 'school_id' => ['nullable', 'integer', 'min:1'], 'class_section_id' => ['nullable', 'integer', 'min:1'], - 'updated_by' => ['nullable', 'integer', 'min:1'], + 'updated_by' => ['nullable', 'integer', 'min:1'], - 'homework_avg' => ['nullable', 'numeric', 'min:0'], - 'quiz_avg' => ['nullable', 'numeric', 'min:0'], - 'project_avg' => ['nullable', 'numeric', 'min:0'], - 'midterm_exam_score' => ['nullable', 'numeric', 'min:0'], - 'final_exam_score' => ['nullable', 'numeric', 'min:0'], - 'attendance_score' => ['nullable', 'numeric', 'min:0'], + 'homework_avg' => ['nullable', 'numeric', 'min:0'], + 'quiz_avg' => ['nullable', 'numeric', 'min:0'], + 'project_avg' => ['nullable', 'numeric', 'min:0'], + 'midterm_exam_score' => ['nullable', 'numeric', 'min:0'], + 'final_exam_score' => ['nullable', 'numeric', 'min:0'], + 'attendance_score' => ['nullable', 'numeric', 'min:0'], 'participation_score' => ['nullable', 'numeric', 'min:0'], - 'ptap_score' => ['nullable', 'numeric', 'min:0'], - 'test_avg' => ['nullable', 'numeric', 'min:0'], - 'semester_score' => ['nullable', 'numeric', 'min:0'], - 'calculation_mode' => ['nullable', 'string', 'in:legacy,strong'], + 'ptap_score' => ['nullable', 'numeric', 'min:0'], + 'test_avg' => ['nullable', 'numeric', 'min:0'], + 'semester_score' => ['nullable', 'numeric', 'min:0'], + 'calculation_mode' => ['nullable', 'string', 'in:legacy,strong'], 'calculation_policy_version' => ['nullable', 'string', 'max:50'], - 'snapshot_id' => ['nullable', 'integer', 'min:1'], + 'snapshot_id' => ['nullable', 'integer', 'min:1'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/SemesterScoreSnapshot.php b/app/Models/SemesterScoreSnapshot.php index 317c95a6..46cc07f0 100644 --- a/app/Models/SemesterScoreSnapshot.php +++ b/app/Models/SemesterScoreSnapshot.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class SemesterScoreSnapshot extends BaseModel diff --git a/app/Models/Setting.php b/app/Models/Setting.php index 0815035d..49c2ac72 100644 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\Cache; @@ -16,7 +17,6 @@ class Setting extends BaseModel 'created_at', 'updated_at', ]; - public $timestamps = true; protected $casts = [ @@ -49,7 +49,7 @@ class Setting extends BaseModel { return static::query()->first() ?? static::query()->create([ // set safe defaults if you want - 'name' => 'App', + 'name' => 'App', 'timezone' => config('app.timezone', 'UTC'), ]); } @@ -70,7 +70,6 @@ class Setting extends BaseModel public static function updateSettings(array $data): bool { $settings = static::singleton(); - return $settings->fill($data)->save(); } @@ -105,9 +104,9 @@ class Setting extends BaseModel public static function rules(bool $updating = false): array { return [ - 'name' => ['nullable', 'string', 'max:255'], - 'timezone' => ['nullable', 'string', 'max:80'], // validate against a list if you want - 'updated_by' => ['nullable', 'integer'], + 'name' => ['nullable', 'string', 'max:255'], + 'timezone' => ['nullable', 'string', 'max:80'], // validate against a list if you want + 'updated_by'=> ['nullable', 'integer'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/Staff.php b/app/Models/Staff.php index a346562d..49ed10db 100644 --- a/app/Models/Staff.php +++ b/app/Models/Staff.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Staff extends BaseModel @@ -29,9 +30,9 @@ class Staff extends BaseModel ]; protected $casts = [ - 'user_id' => 'integer', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'user_id' => 'integer', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -136,7 +137,7 @@ class Staff extends BaseModel // generated email. If an exact school-year row is missing but the user // already has any staff row, update that existing row instead of trying // to insert a duplicate-email record. - if (! $existing) { + if (!$existing) { $existing = static::query() ->where('user_id', $userId) ->orderByDesc('id') @@ -150,11 +151,11 @@ class Staff extends BaseModel if ($existing) { // Preserve original created_at unless explicitly provided - if (! array_key_exists('created_at', $payload) && $existing->created_at) { + if (!array_key_exists('created_at', $payload) && $existing->created_at) { $payload['created_at'] = $existing->created_at; } // Ensure updated_at exists - if (! array_key_exists('updated_at', $payload)) { + if (!array_key_exists('updated_at', $payload)) { $payload['updated_at'] = $now; } @@ -165,10 +166,10 @@ class Staff extends BaseModel } // Insert new row — set created_at/updated_at if not provided - if (! array_key_exists('created_at', $payload)) { + if (!array_key_exists('created_at', $payload)) { $payload['created_at'] = $now; } - if (! array_key_exists('updated_at', $payload)) { + if (!array_key_exists('updated_at', $payload)) { $payload['updated_at'] = $now; } @@ -193,17 +194,17 @@ class Staff extends BaseModel $req = $updating ? 'sometimes' : 'required'; return [ - 'user_id' => [$req, 'integer', 'min:1', 'exists:users,id'], - 'firstname' => ['nullable', 'string', 'max:120'], - 'lastname' => ['nullable', 'string', 'max:120'], - 'email' => ['nullable', 'email', 'max:255'], - 'phone' => ['nullable', 'string', 'max:40'], - 'role_name' => ['nullable', 'string', 'max:80'], - 'active_role' => ['nullable', 'string', 'max:80'], // includes 'inactive' - 'status' => ['nullable', 'string', 'max:40'], - 'school_year' => ['nullable', 'string', 'max:20'], - 'created_at' => ['nullable', 'date'], - 'updated_at' => ['nullable', 'date'], + 'user_id' => [$req, 'integer', 'min:1', 'exists:users,id'], + 'firstname' => ['nullable', 'string', 'max:120'], + 'lastname' => ['nullable', 'string', 'max:120'], + 'email' => ['nullable', 'email', 'max:255'], + 'phone' => ['nullable', 'string', 'max:40'], + 'role_name' => ['nullable', 'string', 'max:80'], + 'active_role' => ['nullable', 'string', 'max:80'], // includes 'inactive' + 'status' => ['nullable', 'string', 'max:40'], + 'school_year' => ['nullable', 'string', 'max:20'], + 'created_at' => ['nullable', 'date'], + 'updated_at' => ['nullable', 'date'], ]; } } diff --git a/app/Models/StaffAttendance.php b/app/Models/StaffAttendance.php index 125d8fbd..c44d94c9 100644 --- a/app/Models/StaffAttendance.php +++ b/app/Models/StaffAttendance.php @@ -3,13 +3,13 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\DB; class StaffAttendance extends BaseModel { protected $table = 'staff_attendance'; - public $timestamps = true; /** @@ -38,13 +38,13 @@ class StaffAttendance extends BaseModel ]; protected $casts = [ - 'user_id' => 'integer', + 'user_id' => 'integer', 'class_section_id' => 'integer', - 'created_by' => 'integer', - 'updated_by' => 'integer', - 'date' => 'date:Y-m-d', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'created_by' => 'integer', + 'updated_by' => 'integer', + 'date' => 'date:Y-m-d', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -52,14 +52,11 @@ class StaffAttendance extends BaseModel * ============================================================ */ public const STATUS_PRESENT = 'present'; - - public const STATUS_ABSENT = 'absent'; - - public const STATUS_LATE = 'late'; + public const STATUS_ABSENT = 'absent'; + public const STATUS_LATE = 'late'; public const POS_MAIN = 'main'; - - public const POS_TA = 'ta'; + public const POS_TA = 'ta'; public static function allowedStatuses(): array { @@ -121,14 +118,12 @@ class StaffAttendance extends BaseModel protected static function normStatus(?string $status): ?string { $s = strtolower(trim((string) $status)); - return in_array($s, self::allowedStatuses(), true) ? $s : null; } protected static function isValidDate(string $d): bool { $dt = date_create_from_format('Y-m-d', $d); - return $dt && $dt->format('Y-m-d') === $d; } @@ -151,7 +146,7 @@ class StaffAttendance extends BaseModel ?string $reason, ?int $editorId = null ): ?self { - if ($userId <= 0 || ! self::isValidDate($date) || $semester === '' || $schoolYear === '') { + if ($userId <= 0 || !self::isValidDate($date) || $semester === '' || $schoolYear === '') { return null; } @@ -163,17 +158,17 @@ class StaffAttendance extends BaseModel $editorId = $editorId ?: (auth()->id() ?? null); $keys = [ - 'user_id' => $userId, - 'date' => $date, - 'semester' => $semester, + 'user_id' => $userId, + 'date' => $date, + 'semester' => $semester, 'school_year' => $schoolYear, ]; $payload = [ - 'role_name' => $roleName, - 'status' => $norm, - 'reason' => $reason ?: null, - 'updated_by' => $editorId, + 'role_name' => $roleName, + 'status' => $norm, + 'reason' => $reason ?: null, + 'updated_by' => $editorId, ]; // Ensure created_by is set on create @@ -199,7 +194,7 @@ class StaffAttendance extends BaseModel ?string $reason = null, ?int $editorId = null ): bool { - if ($userId <= 0 || ! self::isValidDate($date) || $semester === '' || $schoolYear === '') { + if ($userId <= 0 || !self::isValidDate($date) || $semester === '' || $schoolYear === '') { return false; } @@ -217,28 +212,26 @@ class StaffAttendance extends BaseModel if ($existing) { return (bool) $existing->delete(); } - return true; } $keys = [ - 'user_id' => $userId, - 'date' => $date, - 'semester' => $semester, + 'user_id' => $userId, + 'date' => $date, + 'semester' => $semester, 'school_year' => $schoolYear, ]; $payload = [ - 'role_name' => $roleName ?? ($existing->role_name ?? null), + 'role_name' => $roleName ?? ($existing->role_name ?? null), 'class_section_id' => $classSectionId, - 'position' => $position, - 'status' => $norm, - 'reason' => $reason, - 'updated_by' => $editorId, + 'position' => $position, + 'status' => $norm, + 'reason' => $reason, + 'updated_by' => $editorId, ]; static::query()->updateOrCreate($keys, $payload + ['created_by' => $editorId]); - return true; } @@ -250,7 +243,6 @@ class StaffAttendance extends BaseModel public static function deleteOne(int $userId, string $date): bool { $row = static::getOne($userId, $date); - return $row ? (bool) $row->delete() : true; } @@ -284,27 +276,27 @@ class StaffAttendance extends BaseModel ->leftJoinSub($roleSub, 'rs', fn ($j) => $j->on('rs.user_id', '=', 'u.id')) ->leftJoin('staff_attendance as sa', function ($j) use ($date, $semester, $schoolYear) { $j->on('sa.user_id', '=', 'u.id') - ->whereDate('sa.date', '=', $date) - ->where('sa.semester', '=', $semester) - ->where('sa.school_year', '=', $schoolYear); + ->whereDate('sa.date', '=', $date) + ->where('sa.semester', '=', $semester) + ->where('sa.school_year', '=', $schoolYear); }) ->whereNotIn(DB::raw('LOWER(COALESCE(rs.role_name,""))'), ['parent', 'guest']) ->orderBy('u.firstname') ->orderBy('u.lastname'); - if (! empty($excludeUserIds)) { + if (!empty($excludeUserIds)) { $q->whereNotIn('u.id', array_values(array_map('intval', $excludeUserIds))); } return $q->get()->map(function ($r) { return [ - 'user_id' => (int) $r->user_id, - 'firstname' => (string) ($r->firstname ?? ''), - 'lastname' => (string) ($r->lastname ?? ''), - 'role_name' => (string) ($r->role_name ?? ''), - 'satt_id' => $r->satt_id ? (int) $r->satt_id : null, - 'status' => $r->status ? (string) $r->status : null, - 'reason' => $r->reason, + 'user_id' => (int) $r->user_id, + 'firstname' => (string) ($r->firstname ?? ''), + 'lastname' => (string) ($r->lastname ?? ''), + 'role_name' => (string) ($r->role_name ?? ''), + 'satt_id' => $r->satt_id ? (int) $r->satt_id : null, + 'status' => $r->status ? (string) $r->status : null, + 'reason' => $r->reason, ]; })->all(); } @@ -326,10 +318,10 @@ class StaffAttendance extends BaseModel ->get() ->map(fn ($r) => [ 'class_section_id' => (int) $r->class_section_id, - 'teacher_id' => (int) $r->teacher_id, - 'position' => (string) $r->position, - 'firstname' => (string) ($r->firstname ?? ''), - 'lastname' => (string) ($r->lastname ?? ''), + 'teacher_id' => (int) $r->teacher_id, + 'position' => (string) $r->position, + 'firstname' => (string) ($r->firstname ?? ''), + 'lastname' => (string) ($r->lastname ?? ''), ])->all(); } @@ -358,20 +350,20 @@ class StaffAttendance extends BaseModel string $schoolYear ): array { return DB::table('teacher_class as tc') - ->selectRaw(' + ->selectRaw(" tc.class_section_id, tc.teacher_id as teacher_id, tc.position, u.firstname, u.lastname, t.id as satt_id, t.status, t.reason - ') + ") ->join('users as u', 'u.id', '=', 'tc.teacher_id') ->leftJoin('staff_attendance as t', function ($j) use ($date, $semester, $schoolYear) { $j->on('t.user_id', '=', 'tc.teacher_id') - ->on('t.class_section_id', '=', 'tc.class_section_id') - ->whereDate('t.date', '=', $date) - ->where('t.semester', '=', $semester) - ->where('t.school_year', '=', $schoolYear); + ->on('t.class_section_id', '=', 'tc.class_section_id') + ->whereDate('t.date', '=', $date) + ->where('t.semester', '=', $semester) + ->where('t.school_year', '=', $schoolYear); }) ->where('tc.class_section_id', $classSectionId) ->where('tc.school_year', $schoolYear) @@ -380,13 +372,13 @@ class StaffAttendance extends BaseModel ->get() ->map(fn ($r) => [ 'class_section_id' => (int) $r->class_section_id, - 'teacher_id' => (int) $r->teacher_id, - 'position' => (string) $r->position, - 'firstname' => (string) ($r->firstname ?? ''), - 'lastname' => (string) ($r->lastname ?? ''), - 'satt_id' => $r->satt_id ? (int) $r->satt_id : null, - 'status' => $r->status ? strtolower((string) $r->status) : null, - 'reason' => $r->reason, + 'teacher_id' => (int) $r->teacher_id, + 'position' => (string) $r->position, + 'firstname' => (string) ($r->firstname ?? ''), + 'lastname' => (string) ($r->lastname ?? ''), + 'satt_id' => $r->satt_id ? (int) $r->satt_id : null, + 'status' => $r->status ? strtolower((string) $r->status) : null, + 'reason' => $r->reason, ])->all(); } @@ -401,9 +393,7 @@ class StaffAttendance extends BaseModel ->where('school_year', $schoolYear) ->count(); - if ($assigned <= 0) { - return true; - } + if ($assigned <= 0) return true; $present = (int) DB::table('staff_attendance') ->where('class_section_id', $classSectionId) @@ -428,9 +418,7 @@ class StaffAttendance extends BaseModel string $schoolYear ): array { $codes = array_values(array_unique(array_filter(array_map('intval', $sectionCodes)))); - if (empty($codes)) { - return []; - } + if (empty($codes)) return []; $rows = DB::table('staff_attendance') ->selectRaw('class_section_id, user_id, DATE_FORMAT(date,"%Y-%m-%d") as d, status, reason') @@ -452,7 +440,6 @@ class StaffAttendance extends BaseModel 'reason' => $r->reason, ]; } - return $map; } @@ -465,20 +452,20 @@ class StaffAttendance extends BaseModel $req = $updating ? 'sometimes' : 'required'; return [ - 'user_id' => [$req, 'integer', 'min:1', 'exists:users,id'], - 'date' => [$req, 'date_format:Y-m-d'], - 'semester' => [$req, 'string', 'max:20'], + 'user_id' => [$req, 'integer', 'min:1', 'exists:users,id'], + 'date' => [$req, 'date_format:Y-m-d'], + 'semester' => [$req, 'string', 'max:20'], 'school_year' => [$req, 'string', 'max:20'], - 'role_name' => ['nullable', 'string', 'max:80'], - 'status' => ['nullable', 'string', 'in:'.implode(',', self::allowedStatuses())], - 'reason' => ['nullable', 'string', 'max:2000'], + 'role_name' => ['nullable', 'string', 'max:80'], + 'status' => ['nullable', 'string', 'in:' . implode(',', self::allowedStatuses())], + 'reason' => ['nullable', 'string', 'max:2000'], 'class_section_id' => ['nullable', 'integer'], - 'position' => ['nullable', 'string', 'in:'.implode(',', [self::POS_MAIN, self::POS_TA])], + 'position' => ['nullable', 'string', 'in:' . implode(',', [self::POS_MAIN, self::POS_TA])], - 'created_by' => ['nullable', 'integer'], - 'updated_by' => ['nullable', 'integer'], + 'created_by' => ['nullable', 'integer'], + 'updated_by' => ['nullable', 'integer'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/Stats.php b/app/Models/Stats.php index a260abe5..c8e3bf07 100644 --- a/app/Models/Stats.php +++ b/app/Models/Stats.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class Stats extends BaseModel { protected $table = 'stats'; @@ -22,8 +24,8 @@ class Stats extends BaseModel protected $casts = [ 'students' => 'integer', 'teachers' => 'integer', - 'admins' => 'integer', - 'users' => 'integer', + 'admins' => 'integer', + 'users' => 'integer', ]; public function getFillable(): array @@ -49,8 +51,8 @@ class Stats extends BaseModel return static::query()->first() ?? static::query()->create([ 'students' => 0, 'teachers' => 0, - 'admins' => 0, - 'users' => 0, + 'admins' => 0, + 'users' => 0, ]); } @@ -62,7 +64,6 @@ class Stats extends BaseModel $row = static::singleton(); $row->fill($data); $row->save(); - return $row; } } diff --git a/app/Models/Student.php b/app/Models/Student.php index 2dc6ceb4..a3fba3e7 100644 --- a/app/Models/Student.php +++ b/app/Models/Student.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -11,7 +12,6 @@ use Illuminate\Support\Facades\DB; class Student extends BaseModel { use HasFactory; - protected $table = 'students'; /** @@ -31,6 +31,7 @@ class Student extends BaseModel 'is_new', 'parent_id', 'school_year', + 'semester', 'registration_date', 'tuition_paid', 'year_of_registration', @@ -39,15 +40,15 @@ class Student extends BaseModel ]; protected $casts = [ - 'school_id' => 'string', - 'age' => 'integer', - 'photo_consent' => 'boolean', - 'is_new' => 'boolean', - 'parent_id' => 'integer', - 'tuition_paid' => 'boolean', - 'is_active' => 'boolean', - 'dob' => 'date', - 'registration_date' => 'date', + 'school_id' => 'string', + 'age' => 'integer', + 'photo_consent' => 'boolean', + 'is_new' => 'boolean', + 'parent_id' => 'integer', + 'tuition_paid' => 'boolean', + 'is_active' => 'boolean', + 'dob' => 'date', + 'registration_date' => 'date', 'year_of_registration' => 'integer', ]; @@ -97,7 +98,6 @@ class Student extends BaseModel if ($schoolYear === null || strtolower(trim($schoolYear)) === 'all' || trim($schoolYear) === '') { return $q; } - return $q->where('school_year', $schoolYear); } @@ -214,7 +214,6 @@ class Student extends BaseModel public static function getStudentSchoolIdByStudentId(int $studentId): ?string { $v = static::query()->where('id', $studentId)->value('school_id'); - return $v !== null ? (string) $v : null; } @@ -234,16 +233,12 @@ class Student extends BaseModel public static function getFullNameById($studentId): ?array { $student = static::query()->find($studentId); - if (! $student) { - return null; - } + if (!$student) return null; $first = (string) ($student->firstname ?? ''); - $last = (string) ($student->lastname ?? ''); + $last = (string) ($student->lastname ?? ''); - if ($first === '' && $last === '') { - return null; - } + if ($first === '' && $last === '') return null; return ['firstname' => $first, 'lastname' => $last]; } @@ -251,7 +246,7 @@ class Student extends BaseModel /** legacy: getFullName($student array) */ public static function getFullName(array $student): string { - return trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')); + return trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')); } /** legacy: getLastRegistrationDate($ParentId) */ @@ -278,9 +273,7 @@ class Student extends BaseModel ->pluck('student_id') ->all(); - if (empty($studentIds)) { - return []; - } + if (empty($studentIds)) return []; return static::query() ->whereIn('id', $studentIds) @@ -348,9 +341,7 @@ class Student extends BaseModel */ public static function getStudentInfoByClassSectionId(int $classSectionId, ?string $semester = null, ?string $schoolYear = null, ?int $actorId = null): array { - if ($classSectionId <= 0) { - return []; - } + if ($classSectionId <= 0) return []; $q = DB::table('students') ->selectRaw('students.id AS student_id, students.school_id, students.firstname, students.lastname, sc.class_section_id') @@ -385,22 +376,22 @@ class Student extends BaseModel $req = $updating ? 'sometimes' : 'required'; return [ - 'school_id' => ['nullable', 'integer', 'min:1'], - 'firstname' => [$req, 'string', 'max:120'], - 'lastname' => [$req, 'string', 'max:120'], - 'dob' => ['nullable', 'date'], - 'age' => ['nullable', 'integer', 'min:0'], - 'gender' => ['nullable', 'string', 'max:20'], - 'registration_grade' => ['nullable', 'string', 'max:50'], - 'photo_consent' => ['nullable', 'boolean'], - 'is_new' => ['nullable', 'boolean'], - 'parent_id' => ['nullable', 'integer'], - 'school_year' => ['nullable', 'string', 'max:20'], - 'registration_date' => ['nullable', 'date'], - 'tuition_paid' => ['nullable', 'boolean'], - 'year_of_registration' => ['nullable', 'integer', 'min:0'], - 'rfid_tag' => ['nullable', 'string', 'max:120'], - 'is_active' => ['nullable', 'boolean'], + 'school_id' => ['nullable', 'integer', 'min:1'], + 'firstname' => [$req, 'string', 'max:120'], + 'lastname' => [$req, 'string', 'max:120'], + 'dob' => ['nullable', 'date'], + 'age' => ['nullable', 'integer', 'min:0'], + 'gender' => ['nullable', 'string', 'max:20'], + 'registration_grade' => ['nullable', 'string', 'max:50'], + 'photo_consent' => ['nullable', 'boolean'], + 'is_new' => ['nullable', 'boolean'], + 'parent_id' => ['nullable', 'integer'], + 'school_year' => ['nullable', 'string', 'max:20'], + 'registration_date' => ['nullable', 'date'], + 'tuition_paid' => ['nullable', 'boolean'], + 'year_of_registration'=> ['nullable', 'integer', 'min:0'], + 'rfid_tag' => ['nullable', 'string', 'max:120'], + 'is_active' => ['nullable', 'boolean'], ]; } } diff --git a/app/Models/StudentAllergy.php b/app/Models/StudentAllergy.php index 11d7fc2b..83c1ea7b 100644 --- a/app/Models/StudentAllergy.php +++ b/app/Models/StudentAllergy.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class StudentAllergy extends BaseModel @@ -46,7 +47,6 @@ class StudentAllergy extends BaseModel public function scopeForStudents(Builder $q, array $studentIds): Builder { $ids = array_values(array_unique(array_filter(array_map('intval', $studentIds)))); - return empty($ids) ? $q->whereRaw('1=0') : $q->whereIn('student_id', $ids); } @@ -103,7 +103,7 @@ class StudentAllergy extends BaseModel return [ 'student_id' => [$req, 'integer', 'min:1', 'exists:students,id'], - 'allergy' => [$req, 'string', 'max:100'], + 'allergy' => [$req, 'string', 'max:100'], ]; } @@ -111,9 +111,9 @@ class StudentAllergy extends BaseModel { return [ 'student_id.required' => 'Student ID is required.', - 'student_id.min' => 'Invalid Student ID.', - 'allergy.required' => 'Allergy is required.', - 'allergy.max' => 'Allergy must be 100 characters or fewer.', + 'student_id.min' => 'Invalid Student ID.', + 'allergy.required' => 'Allergy is required.', + 'allergy.max' => 'Allergy must be 100 characters or fewer.', ]; } -} +} \ No newline at end of file diff --git a/app/Models/StudentClass.php b/app/Models/StudentClass.php index 47d3584b..70bd4d2d 100644 --- a/app/Models/StudentClass.php +++ b/app/Models/StudentClass.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\DB; @@ -22,17 +23,16 @@ class StudentClass extends BaseModel 'updated_at', 'created_at', ]; - public $timestamps = true; protected $casts = [ - 'student_id' => 'integer', - 'school_id' => 'integer', + 'student_id' => 'integer', + 'school_id' => 'integer', 'class_section_id' => 'integer', - 'is_event_only' => 'boolean', - 'updated_by' => 'integer', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'is_event_only' => 'boolean', + 'updated_by' => 'integer', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -84,10 +84,7 @@ class StudentClass extends BaseModel public function scopeForYear(Builder $q, ?string $schoolYear): Builder { - if ($schoolYear === null || trim($schoolYear) === '') { - return $q; - } - + if ($schoolYear === null || trim($schoolYear) === '') return $q; return $q->where('student_class.school_year', $schoolYear); } @@ -137,12 +134,12 @@ class StudentClass extends BaseModel ->where('sc.school_year', $schoolYear) ->orderBy('cs.class_section_name', 'asc') ->pluck('cs.class_section_name') - ->filter(fn ($v) => $v !== null && trim((string) $v) !== '') + ->filter(fn ($v) => $v !== null && trim((string)$v) !== '') ->unique() ->values() ->all(); - return $asArray ? $names : (! empty($names) ? implode(', ', $names) : ''); + return $asArray ? $names : (!empty($names) ? implode(', ', $names) : ''); } /** @@ -165,17 +162,15 @@ class StudentClass extends BaseModel $names = []; foreach ($rows as $r) { $name = $r->class_section_name ?? null; - if (! $name) { - continue; - } + if (!$name) continue; - $isEvent = (int) ($r->is_event_only ?? 0) === 1; - $names[] = $isEvent ? ($name.' (Event)') : $name; + $isEvent = (int)($r->is_event_only ?? 0) === 1; + $names[] = $isEvent ? ($name . ' (Event)') : $name; } $names = array_values(array_unique(array_filter($names))); - return $asArray ? $names : (! empty($names) ? implode(', ', $names) : ''); + return $asArray ? $names : (!empty($names) ? implode(', ', $names) : ''); } /** @@ -205,9 +200,7 @@ class StudentClass extends BaseModel public static function getStudentsByClassSectionIds(array $classSectionIds): array { $ids = array_values(array_unique(array_filter(array_map('intval', $classSectionIds)))); - if (empty($ids)) { - return []; - } + if (empty($ids)) return []; return DB::table('student_class as sc') ->selectRaw(' @@ -241,7 +234,7 @@ class StudentClass extends BaseModel ->orderByDesc('created_at') ->first(); - if (! $sc || ! $sc->class_section_id) { + if (!$sc || !$sc->class_section_id) { return 'N/A'; } @@ -289,9 +282,7 @@ class StudentClass extends BaseModel $out = []; foreach ($rows as $r) { $cid = $r->class_section_id; - if ($cid === null || $cid === '') { - continue; - } + if ($cid === null || $cid === '') continue; $out[$cid] = (int) ($r->total ?? 0); } @@ -307,13 +298,13 @@ class StudentClass extends BaseModel $req = $updating ? 'sometimes' : 'required'; return [ - 'student_id' => [$req, 'integer', 'min:1', 'exists:students,id'], - 'school_id' => ['nullable', 'integer', 'min:1'], + 'student_id' => [$req, 'integer', 'min:1', 'exists:students,id'], + 'school_id' => ['nullable', 'integer', 'min:1'], 'class_section_id' => ['nullable', 'integer'], - 'school_year' => [$req, 'string', 'max:20'], - 'is_event_only' => ['nullable', 'boolean'], - 'description' => ['nullable', 'string', 'max:2000'], - 'updated_by' => ['nullable', 'integer'], + 'school_year' => [$req, 'string', 'max:20'], + 'is_event_only' => ['nullable', 'boolean'], + 'description' => ['nullable', 'string', 'max:2000'], + 'updated_by' => ['nullable', 'integer'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/StudentMedicalCondition.php b/app/Models/StudentMedicalCondition.php index c89aefbb..2f1209ff 100644 --- a/app/Models/StudentMedicalCondition.php +++ b/app/Models/StudentMedicalCondition.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class StudentMedicalCondition extends BaseModel @@ -46,7 +47,6 @@ class StudentMedicalCondition extends BaseModel public function scopeForStudents(Builder $q, array $studentIds): Builder { $ids = array_values(array_unique(array_filter(array_map('intval', $studentIds)))); - return empty($ids) ? $q->whereRaw('1=0') : $q->whereIn('student_id', $ids); } @@ -100,7 +100,7 @@ class StudentMedicalCondition extends BaseModel $req = $updating ? 'sometimes' : 'required'; return [ - 'student_id' => [$req, 'integer', 'min:1', 'exists:students,id'], + 'student_id' => [$req, 'integer', 'min:1', 'exists:students,id'], 'condition_name' => [$req, 'string', 'max:100'], ]; } @@ -108,10 +108,10 @@ class StudentMedicalCondition extends BaseModel public static function messages(): array { return [ - 'student_id.required' => 'Student ID is required.', - 'student_id.min' => 'Invalid Student ID.', + 'student_id.required' => 'Student ID is required.', + 'student_id.min' => 'Invalid Student ID.', 'condition_name.required' => 'Condition name is required.', - 'condition_name.max' => 'Condition name must be 100 characters or fewer.', + 'condition_name.max' => 'Condition name must be 100 characters or fewer.', ]; } -} +} \ No newline at end of file diff --git a/app/Models/StudentPromotionRecord.php b/app/Models/StudentPromotionRecord.php index a978301a..1611f7ae 100644 --- a/app/Models/StudentPromotionRecord.php +++ b/app/Models/StudentPromotionRecord.php @@ -16,39 +16,25 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; class StudentPromotionRecord extends BaseModel { protected $table = 'student_promotion_records'; - protected $primaryKey = 'promotion_id'; public $timestamps = true; public const STATUS_NOT_REVIEWED = 'not_reviewed'; - public const STATUS_ELIGIBLE = 'eligible_for_promotion'; - public const STATUS_AWAITING_PARENT = 'awaiting_parent_enrollment'; - public const STATUS_ENROLLMENT_STARTED = 'enrollment_started'; - public const STATUS_PROMOTED_AND_ENROLLED = 'promoted_and_enrolled'; - public const STATUS_CONDITIONAL = 'conditional_promotion'; - public const STATUS_REPEATED = 'repeated_level'; - public const STATUS_ON_HOLD = 'on_hold'; - public const STATUS_WITHDRAWN = 'withdrawn'; - public const STATUS_GRADUATED = 'graduated'; - public const STATUS_NOT_ENROLLED = 'not_enrolled_for_next_year'; public const ENROLLMENT_NOT_STARTED = 'not_started'; - public const ENROLLMENT_IN_PROGRESS = 'in_progress'; - public const ENROLLMENT_COMPLETED = 'completed'; - public const ENROLLMENT_EXPIRED = 'expired'; public const ALL_STATUSES = [ diff --git a/app/Models/SubjectCurriculum.php b/app/Models/SubjectCurriculum.php index 8652bda2..c0196437 100644 --- a/app/Models/SubjectCurriculum.php +++ b/app/Models/SubjectCurriculum.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\Schema; @@ -20,14 +21,13 @@ class SubjectCurriculum extends BaseModel 'created_at', 'updated_at', ]; - public $timestamps = true; protected $casts = [ - 'class_id' => 'integer', - 'unit_number' => 'integer', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'class_id' => 'integer', + 'unit_number' => 'integer', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -59,7 +59,7 @@ class SubjectCurriculum extends BaseModel public function scopeForSchoolYear(Builder $q, ?string $schoolYear): Builder { $schoolYear = trim((string) $schoolYear); - if ($schoolYear === '' || ! Schema::hasColumn($this->getTable(), 'school_year')) { + if ($schoolYear === '' || !Schema::hasColumn($this->getTable(), 'school_year')) { return $q; } @@ -69,7 +69,7 @@ class SubjectCurriculum extends BaseModel public function scopeOrdered(Builder $q): Builder { return $q->orderBy('unit_number', 'asc') - ->orderBy('chapter_name', 'asc'); + ->orderBy('chapter_name', 'asc'); } /* ============================================================ @@ -112,7 +112,7 @@ class SubjectCurriculum extends BaseModel ->get() ->map(fn ($r) => [ 'unit_number' => (int) $r->unit_number, - 'unit_title' => (string) ($r->unit_title ?? ''), + 'unit_title' => (string) ($r->unit_title ?? ''), ]) ->all(); } @@ -131,7 +131,7 @@ class SubjectCurriculum extends BaseModel ->orderBy('chapter_name', 'asc') ->distinct() ->pluck('chapter_name') - ->filter(fn ($v) => $v !== null && trim((string) $v) !== '') + ->filter(fn ($v) => $v !== null && trim((string)$v) !== '') ->values() ->all(); } @@ -146,11 +146,11 @@ class SubjectCurriculum extends BaseModel $req = $updating ? 'sometimes' : 'required'; return [ - 'class_id' => [$req, 'integer', 'min:1'], - 'subject' => [$req, 'string', 'max:120'], - 'unit_number' => ['nullable', 'integer', 'min:0'], - 'unit_title' => ['nullable', 'string', 'max:255'], - 'chapter_name' => ['nullable', 'string', 'max:255'], + 'class_id' => [$req, 'integer', 'min:1'], + 'subject' => [$req, 'string', 'max:120'], + 'unit_number' => ['nullable', 'integer', 'min:0'], + 'unit_title' => ['nullable', 'string', 'max:255'], + 'chapter_name' => ['nullable', 'string', 'max:255'], ]; } } diff --git a/app/Models/Supplier.php b/app/Models/Supplier.php index bd9c79c7..47980b7e 100644 --- a/app/Models/Supplier.php +++ b/app/Models/Supplier.php @@ -2,10 +2,11 @@ namespace App\Models; +use App\Models\BaseModel; + class Supplier extends BaseModel { protected $table = 'suppliers'; - public $timestamps = true; protected $fillable = [ diff --git a/app/Models/Supply.php b/app/Models/Supply.php index cc0201f0..162cf2e6 100644 --- a/app/Models/Supply.php +++ b/app/Models/Supply.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class Supply extends BaseModel { protected $table = 'supplies'; diff --git a/app/Models/SupplyCategory.php b/app/Models/SupplyCategory.php index 00d58c46..8f422b09 100644 --- a/app/Models/SupplyCategory.php +++ b/app/Models/SupplyCategory.php @@ -2,10 +2,11 @@ namespace App\Models; +use App\Models\BaseModel; + class SupplyCategory extends BaseModel { protected $table = 'supply_categories'; - public $timestamps = true; protected $fillable = [ diff --git a/app/Models/SupplyTransaction.php b/app/Models/SupplyTransaction.php index 1d566b84..9367af3e 100644 --- a/app/Models/SupplyTransaction.php +++ b/app/Models/SupplyTransaction.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Models\BaseModel; + class SupplyTransaction extends BaseModel { protected $table = 'supply_transactions'; diff --git a/app/Models/SupportRequest.php b/app/Models/SupportRequest.php index 78234c41..7c4bb6c6 100644 --- a/app/Models/SupportRequest.php +++ b/app/Models/SupportRequest.php @@ -2,10 +2,11 @@ namespace App\Models; +use App\Models\BaseModel; + class SupportRequest extends BaseModel { protected $table = 'support_requests'; - public $timestamps = true; protected $fillable = [ diff --git a/app/Models/Teacher.php b/app/Models/Teacher.php index dd51c42c..826cac19 100644 --- a/app/Models/Teacher.php +++ b/app/Models/Teacher.php @@ -2,4 +2,6 @@ namespace App\Models; -class Teacher extends User {} +class Teacher extends User +{ +} diff --git a/app/Models/TeacherClass.php b/app/Models/TeacherClass.php index 2471096d..051f954c 100644 --- a/app/Models/TeacherClass.php +++ b/app/Models/TeacherClass.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\DB; @@ -20,30 +21,30 @@ class TeacherClass extends BaseModel 'updated_at', 'created_at', ]; - public $timestamps = true; protected $casts = [ - 'teacher_id' => 'integer', + 'teacher_id' => 'integer', 'class_section_id' => 'integer', - 'updated_by' => 'integer', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'updated_by' => 'integer', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; + /* ============================================================ * Constants * ============================================================ */ public const POS_MAIN = 'main'; - - public const POS_TA = 'ta'; + public const POS_TA = 'ta'; public static function allowedPositions(): array { return [self::POS_MAIN, self::POS_TA]; } + /* ============================================================ * Relationships (optional) * ============================================================ @@ -137,15 +138,15 @@ class TeacherClass extends BaseModel return $rows->map(function ($r) use ($semester) { return [ - 'class_section_pk' => isset($r->class_section_pk) ? (int) $r->class_section_pk : null, - 'class_section_id' => (int) $r->class_section_id, + 'class_section_pk' => isset($r->class_section_pk) ? (int) $r->class_section_pk : null, + 'class_section_id' => (int) $r->class_section_id, 'class_section_name' => (string) $r->class_section_name, - 'class_id' => isset($r->class_id) ? (int) $r->class_id : null, - 'class_name' => $r->class_name ?? null, - 'teacher_id' => (int) $r->teacher_id, - 'teacher_role' => ucfirst((string) $r->position), // Main / Ta - 'school_year' => (string) $r->school_year, - 'semester' => $semester, + 'class_id' => isset($r->class_id) ? (int) $r->class_id : null, + 'class_name' => $r->class_name ?? null, + 'teacher_id' => (int) $r->teacher_id, + 'teacher_role' => ucfirst((string) $r->position), // Main / Ta + 'school_year' => (string) $r->school_year, + 'semester' => $semester, ]; })->all(); } @@ -213,21 +214,15 @@ class TeacherClass extends BaseModel $classSectionName = trim($classSectionName); if (str_contains($classSectionName, ',')) { $parts = array_values(array_filter(array_map('trim', explode(',', $classSectionName)))); - if (! empty($parts)) { - $classSectionName = $parts[0]; - } - } - if ($classSectionName === '') { - return null; + if (!empty($parts)) $classSectionName = $parts[0]; } + if ($classSectionName === '') return null; $sectionCode = DB::table('classSection') ->where('class_section_name', $classSectionName) ->value('class_section_id'); - if (! $sectionCode) { - return null; - } + if (!$sectionCode) return null; $teacherId = DB::table('teacher_class') ->where('class_section_id', $sectionCode) @@ -269,7 +264,7 @@ class TeacherClass extends BaseModel ?int $updatedBy = null ): bool { $position = strtolower(trim($position)); - if (! in_array($position, self::allowedPositions(), true)) { + if (!in_array($position, self::allowedPositions(), true)) { throw new \InvalidArgumentException('Position must be either "main" or "ta".'); } @@ -277,10 +272,10 @@ class TeacherClass extends BaseModel static::query()->updateOrCreate( [ - 'teacher_id' => $teacherId, + 'teacher_id' => $teacherId, 'class_section_id' => $sectionCode, - 'school_year' => $schoolYear, - 'position' => $position, + 'school_year' => $schoolYear, + 'position' => $position, ], [ 'updated_by' => $updatedBy, @@ -314,7 +309,7 @@ class TeacherClass extends BaseModel * Returns rows: class_section_id, teacher_id, position, firstname, lastname * * @param int|null $alsoSectionCode When teacher_class rows use the section PK while $sectionCode - * is the business code (or the reverse), pass the other id. + * is the business code (or the reverse), pass the other id. * @param bool $requireSemester When false, ignore semester (legacy DBs with blank/wrong tc.semester). */ public static function assignedForSectionTerm( @@ -365,7 +360,6 @@ class TeacherClass extends BaseModel foreach (static::assignedForSectionTerm($sectionCode, $semester, $schoolYear, $alsoSectionCode, $requireSemester) as $r) { $out[(int) $r['teacher_id']] = $r; } - return $out; } @@ -383,11 +377,9 @@ class TeacherClass extends BaseModel ->orderByRaw("CASE tc.position WHEN 'main' THEN 0 WHEN 'ta' THEN 1 ELSE 2 END") ->orderBy('u.firstname', 'asc'); - if (! empty($onlySectionCodes)) { + if (!empty($onlySectionCodes)) { $ids = array_values(array_unique(array_filter(array_map('intval', $onlySectionCodes)))); - if (! empty($ids)) { - $q->whereIn('tc.class_section_id', $ids); - } + if (!empty($ids)) $q->whereIn('tc.class_section_id', $ids); } $rows = $q->get()->map(fn ($r) => (array) $r)->all(); @@ -395,9 +387,7 @@ class TeacherClass extends BaseModel $out = []; foreach ($rows as $r) { $code = (int) ($r['class_section_id'] ?? 0); - if ($code <= 0) { - continue; - } + if ($code <= 0) continue; $out[$code][] = $r; } @@ -413,12 +403,12 @@ class TeacherClass extends BaseModel $req = $updating ? 'sometimes' : 'required'; return [ - 'teacher_id' => [$req, 'integer', 'min:1', 'exists:users,id'], + 'teacher_id' => [$req, 'integer', 'min:1', 'exists:users,id'], 'class_section_id' => [$req, 'integer', 'min:1'], - 'semester' => [$req, 'string', 'max:25'], - 'school_year' => [$req, 'string', 'max:9'], - 'position' => [$req, 'string', 'in:'.implode(',', self::allowedPositions())], - 'updated_by' => ['nullable', 'integer'], + 'semester' => [$req, 'string', 'max:25'], + 'school_year' => [$req, 'string', 'max:9'], + 'position' => [$req, 'string', 'in:' . implode(',', self::allowedPositions())], + 'updated_by' => ['nullable', 'integer'], ]; } } diff --git a/app/Models/TeacherSubmissionNotificationHistory.php b/app/Models/TeacherSubmissionNotificationHistory.php index 1bfe8cd6..294ac2fe 100644 --- a/app/Models/TeacherSubmissionNotificationHistory.php +++ b/app/Models/TeacherSubmissionNotificationHistory.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class TeacherSubmissionNotificationHistory extends BaseModel @@ -27,10 +28,10 @@ class TeacherSubmissionNotificationHistory extends BaseModel ]; protected $casts = [ - 'teacher_id' => 'integer', + 'teacher_id' => 'integer', 'class_section_id' => 'integer', - 'admin_id' => 'integer', - 'sent_at' => 'datetime', + 'admin_id' => 'integer', + 'sent_at' => 'datetime', ]; /* ============================================================ @@ -74,7 +75,7 @@ class TeacherSubmissionNotificationHistory extends BaseModel public function scopeForTerm(Builder $q, string $schoolYear, string $semester): Builder { return $q->where('school_year', $schoolYear) - ->where('semester', $semester); + ->where('semester', $semester); } public function scopeCategory(Builder $q, string $category): Builder @@ -112,15 +113,15 @@ class TeacherSubmissionNotificationHistory extends BaseModel $req = $updating ? 'sometimes' : 'required'; return [ - 'teacher_id' => [$req, 'integer', 'min:1', 'exists:users,id'], - 'class_section_id' => ['nullable', 'integer'], - 'admin_id' => ['nullable', 'integer', 'exists:users,id'], - 'notification_category' => [$req, 'string', 'max:120'], - 'message' => [$req, 'string', 'max:5000'], - 'status' => ['nullable', 'string', 'max:50'], - 'school_year' => ['nullable', 'string', 'max:20'], - 'semester' => ['nullable', 'string', 'max:20'], - 'sent_at' => ['nullable', 'date'], + 'teacher_id' => [$req, 'integer', 'min:1', 'exists:users,id'], + 'class_section_id' => ['nullable', 'integer'], + 'admin_id' => ['nullable', 'integer', 'exists:users,id'], + 'notification_category' => [$req, 'string', 'max:120'], + 'message' => [$req, 'string', 'max:5000'], + 'status' => ['nullable', 'string', 'max:50'], + 'school_year' => ['nullable', 'string', 'max:20'], + 'semester' => ['nullable', 'string', 'max:20'], + 'sent_at' => ['nullable', 'date'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/User.php b/app/Models/User.php index 4f920ecc..2ad96b72 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,9 +4,9 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Schema; @@ -58,14 +58,14 @@ class User extends Authenticatable implements JWTSubject ]; protected $casts = [ - 'school_id' => 'integer', - 'failed_attempts' => 'integer', - 'last_failed_at' => 'datetime', - 'accept_school_policy' => 'boolean', - 'is_suspended' => 'boolean', - 'is_verified' => 'boolean', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'school_id' => 'integer', + 'failed_attempts' => 'integer', + 'last_failed_at' => 'datetime', + 'accept_school_policy' => 'boolean', + 'is_suspended' => 'boolean', + 'is_verified' => 'boolean', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; public function getJWTIdentifier() @@ -176,7 +176,7 @@ class User extends Authenticatable implements JWTSubject $pivotColumns[] = 'school_year'; } - if (! empty($pivotColumns)) { + if (!empty($pivotColumns)) { $relation->withPivot($pivotColumns); } @@ -218,7 +218,7 @@ class User extends Authenticatable implements JWTSubject public function scopeHasAnyRoleNames(Builder $q, array $roleNames): Builder { $names = array_values(array_unique(array_filter(array_map( - fn ($v) => strtolower(trim((string) $v)), + fn($v) => strtolower(trim((string)$v)), $roleNames )))); @@ -267,10 +267,8 @@ class User extends Authenticatable implements JWTSubject $order = strtolower($order) === 'desc' ? 'desc' : 'asc'; // whitelist to prevent SQL injection - $allowedSort = ['users.id', 'users.firstname', 'users.lastname', 'users.email', 'role']; - if (! in_array($sort, $allowedSort, true)) { - $sort = 'users.id'; - } + $allowedSort = ['users.id','users.firstname','users.lastname','users.email','role']; + if (!in_array($sort, $allowedSort, true)) $sort = 'users.id'; $q = DB::table('users') ->select('users.id', 'users.firstname', 'users.lastname', 'users.email', DB::raw('roles.name as role')) @@ -279,12 +277,12 @@ class User extends Authenticatable implements JWTSubject // sorting "role" alias requires orderByRaw if ($sort === 'role') { - $q->orderByRaw('role '.strtoupper($order)); + $q->orderByRaw('role ' . strtoupper($order)); } else { $q->orderBy($sort, $order); } - return $q->get()->map(fn ($r) => (array) $r)->all(); + return $q->get()->map(fn($r) => (array) $r)->all(); } /** @@ -314,16 +312,14 @@ class User extends Authenticatable implements JWTSubject // whitelist sort fields $allowedSort = [ - 'users.id', 'users.firstname', 'users.lastname', 'users.email', 'users.cellphone', - 'users.school_year', 'users.status', 'users.created_at', 'users.updated_at', + 'users.id','users.firstname','users.lastname','users.email','users.cellphone', + 'users.school_year','users.status','users.created_at','users.updated_at' ]; - if (! in_array($sort, $allowedSort, true)) { - $sort = 'users.id'; - } + if (!in_array($sort, $allowedSort, true)) $sort = 'users.id'; $q = static::query(); - if (! empty($conditions)) { + if (!empty($conditions)) { $q->where($conditions); } @@ -333,7 +329,7 @@ class User extends Authenticatable implements JWTSubject $q->skip($offset)->take($limit); } - return $q->get()->map(fn ($u) => $u->toArray())->all(); + return $q->get()->map(fn($u) => $u->toArray())->all(); } /** @@ -357,7 +353,6 @@ class User extends Authenticatable implements JWTSubject public static function getAllUsers(string $sort = 'users.id', string $order = 'asc') { $order = strtolower($order) === 'desc' ? 'desc' : 'asc'; - return static::query()->orderBy($sort, $order)->get(); } @@ -369,17 +364,15 @@ class User extends Authenticatable implements JWTSubject { $user = static::query() ->select([ - 'id', 'account_id', 'lastname', 'firstname', 'gender', 'cellphone', 'email', - 'address_street', 'apt', 'city', 'state', 'zip', 'accept_school_policy', - 'user_type', 'rfid_tag', 'school_id', 'failed_attempts', 'last_failed_at', - 'semester', 'school_year', 'status', 'is_suspended', 'created_at', 'updated_at', + 'id','account_id','lastname','firstname','gender','cellphone','email', + 'address_street','apt','city','state','zip','accept_school_policy', + 'user_type','rfid_tag','school_id','failed_attempts','last_failed_at', + 'semester','school_year','status','is_suspended','created_at','updated_at', ]) ->where('id', $userId) ->first(); - if (! $user) { - return null; - } + if (!$user) return null; $roles = DB::table('user_roles as ur') ->select('r.id', 'r.name', 'r.slug') @@ -387,7 +380,7 @@ class User extends Authenticatable implements JWTSubject ->where('ur.user_id', $userId) ->whereNull('ur.deleted_at') ->get() - ->map(fn ($r) => (array) $r) + ->map(fn($r) => (array) $r) ->all(); $arr = $user->toArray(); @@ -408,7 +401,7 @@ class User extends Authenticatable implements JWTSubject ->where('roles.name', $roleName) ->whereNull('user_roles.deleted_at') ->get() - ->map(fn ($r) => (array) $r) + ->map(fn($r) => (array) $r) ->all(); } @@ -425,7 +418,7 @@ class User extends Authenticatable implements JWTSubject ->where('users.school_year', $schoolYear) ->whereNull('user_roles.deleted_at') ->get() - ->map(fn ($r) => (array) $r) + ->map(fn($r) => (array) $r) ->all(); } @@ -452,7 +445,6 @@ class User extends Authenticatable implements JWTSubject public static function getSchoolIdByUserId(int $userId): ?int { $v = static::query()->where('id', $userId)->value('school_id'); - return $v === null ? null : (int) $v; } @@ -466,9 +458,7 @@ class User extends Authenticatable implements JWTSubject ->whereRaw('LOWER(name) = ?', ['parent']) ->value('id'); - if (! $parentRoleId) { - return []; - } + if (!$parentRoleId) return []; return DB::table('users') ->select('users.id', 'users.firstname', 'users.lastname', 'users.email', 'users.school_id') @@ -477,7 +467,7 @@ class User extends Authenticatable implements JWTSubject ->whereNull('user_roles.deleted_at') ->groupBy('users.id', 'users.firstname', 'users.lastname', 'users.email', 'users.school_id') ->get() - ->map(fn ($r) => (array) $r) + ->map(fn($r) => (array) $r) ->all(); } @@ -521,9 +511,7 @@ class User extends Authenticatable implements JWTSubject // whitelist sort fields $allowedSort = ['users.id', 'users.firstname', 'users.lastname', 'users.email', 'roles']; - if (! in_array($sort, $allowedSort, true)) { - $sort = 'users.lastname'; - } + if (!in_array($sort, $allowedSort, true)) $sort = 'users.lastname'; $q = DB::table('users') ->selectRaw(" @@ -538,14 +526,12 @@ class User extends Authenticatable implements JWTSubject ->whereNull('ur.deleted_at') ->whereNotIn(DB::raw('LOWER(r.name)'), ['parent', 'guest']); // drop parent/guest - if (! empty($selectedUserIds)) { + if (!empty($selectedUserIds)) { $ids = array_values(array_unique(array_filter(array_map('intval', $selectedUserIds)))); - if (! empty($ids)) { - $q->whereIn('users.id', $ids); - } + if (!empty($ids)) $q->whereIn('users.id', $ids); } - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { // Prefer ur.school_year if it exists (role is year-scoped) $hasUrSchoolYear = false; try { @@ -595,7 +581,7 @@ class User extends Authenticatable implements JWTSubject $q->orderBy($sort, strtolower($order)); } - return $q->get()->map(fn ($r) => (array) $r)->all(); + return $q->get()->map(fn($r) => (array) $r)->all(); } /* ============================================================ @@ -615,7 +601,7 @@ class User extends Authenticatable implements JWTSubject ->orderBy('users.lastname', 'asc') ->orderBy('users.firstname', 'asc') ->get() - ->map(fn ($u) => $u->toArray()) + ->map(fn($u) => $u->toArray()) ->all(); } @@ -636,7 +622,7 @@ class User extends Authenticatable implements JWTSubject ->orderBy('u.lastname', 'asc') ->orderBy('u.firstname', 'asc') ->get() - ->map(fn ($r) => (array) $r) + ->map(fn($r) => (array) $r) ->all(); } @@ -678,7 +664,7 @@ class User extends Authenticatable implements JWTSubject ->orderBy('users.lastname', 'asc') ->orderBy('users.firstname', 'asc') ->get() - ->map(fn ($r) => (array) $r) + ->map(fn($r) => (array) $r) ->all(); } @@ -690,15 +676,15 @@ class User extends Authenticatable implements JWTSubject public static function registrationRules(): array { return [ - 'password' => ['required', 'string', 'min:8', 'regex:/[A-Z]/', 'regex:/[a-z]/', 'regex:/[0-9]/', 'regex:/[\W_]/'], - 'lastname' => ['required', 'string', 'max:120'], - 'firstname' => ['required', 'string', 'max:120'], - 'cellphone' => ['required', 'regex:/^\d{10}$/'], - 'email' => ['required', 'email', 'max:255'], - 'address_street' => ['required', 'string', 'max:255'], - 'city' => ['required', 'string', 'max:120'], - 'state' => ['required', 'regex:/^[A-Z]{2}$/'], - 'zip' => ['required', 'regex:/^\d{5}(-\d{4})?$/'], + 'password' => ['required', 'string', 'min:8', 'regex:/[A-Z]/', 'regex:/[a-z]/', 'regex:/[0-9]/', 'regex:/[\W_]/'], + 'lastname' => ['required', 'string', 'max:120'], + 'firstname' => ['required', 'string', 'max:120'], + 'cellphone' => ['required', 'regex:/^\d{10}$/'], + 'email' => ['required', 'email', 'max:255'], + 'address_street' => ['required', 'string', 'max:255'], + 'city' => ['required', 'string', 'max:120'], + 'state' => ['required', 'regex:/^[A-Z]{2}$/'], + 'zip' => ['required', 'regex:/^\d{5}(-\d{4})?$/'], 'accept_school_policy' => ['required', 'in:1,true,on'], ]; } @@ -720,12 +706,10 @@ class User extends Authenticatable implements JWTSubject */ public function setPasswordAttribute($value): void { - if ($value === null || $value === '') { - return; - } + if ($value === null || $value === '') return; // Avoid double-hashing - $this->attributes['password'] = str_starts_with((string) $value, '$2y$') + $this->attributes['password'] = str_starts_with((string)$value, '$2y$') ? $value : Hash::make($value); } diff --git a/app/Models/UserNotification.php b/app/Models/UserNotification.php index b2bcd8bc..bbd394a3 100644 --- a/app/Models/UserNotification.php +++ b/app/Models/UserNotification.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class UserNotification extends BaseModel @@ -24,10 +25,10 @@ class UserNotification extends BaseModel protected $casts = [ 'notification_id' => 'integer', - 'user_id' => 'integer', - 'is_read' => 'boolean', - 'delivered' => 'boolean', - 'delivered_at' => 'datetime', + 'user_id' => 'integer', + 'is_read' => 'boolean', + 'delivered' => 'boolean', + 'delivered_at' => 'datetime', ]; /* ============================================================ @@ -111,10 +112,10 @@ class UserNotification extends BaseModel return [ 'notification_id' => [$req, 'integer', 'min:1', 'exists:notifications,id'], - 'user_id' => [$req, 'integer', 'min:1', 'exists:users,id'], - 'is_read' => ['nullable', 'boolean'], - 'delivered' => ['nullable', 'boolean'], - 'delivered_at' => ['nullable', 'date'], + 'user_id' => [$req, 'integer', 'min:1', 'exists:users,id'], + 'is_read' => ['nullable', 'boolean'], + 'delivered' => ['nullable', 'boolean'], + 'delivered_at' => ['nullable', 'date'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/UserRole.php b/app/Models/UserRole.php index 383157b1..0c65ccce 100644 --- a/app/Models/UserRole.php +++ b/app/Models/UserRole.php @@ -3,8 +3,9 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\Relations\BelongsTo; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\DB; class UserRole extends BaseModel @@ -27,12 +28,12 @@ class UserRole extends BaseModel ]; protected $casts = [ - 'user_id' => 'integer', - 'role_id' => 'integer', - 'updated_by' => 'integer', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', - 'deleted_at' => 'datetime', + 'user_id' => 'integer', + 'role_id' => 'integer', + 'updated_by' => 'integer', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + 'deleted_at' => 'datetime', ]; /* ============================================================ @@ -67,10 +68,7 @@ class UserRole extends BaseModel public function scopeForSchoolYear(Builder $q, ?string $schoolYear): Builder { - if ($schoolYear === null || trim($schoolYear) === '') { - return $q; - } - + if ($schoolYear === null || trim($schoolYear) === '') return $q; return $q->where('school_year', $schoolYear); } @@ -120,13 +118,12 @@ class UserRole extends BaseModel $existing->updated_by = $editorId; $existing->save(); } - return true; } static::query()->create([ - 'user_id' => $userId, - 'role_id' => $roleId, + 'user_id' => $userId, + 'role_id' => $roleId, 'updated_by' => $editorId, ]); @@ -173,11 +170,11 @@ class UserRole extends BaseModel $req = $updating ? 'sometimes' : 'required'; return [ - 'user_id' => [$req, 'integer', 'min:1', 'exists:users,id'], - 'role_id' => [$req, 'integer', 'min:1', 'exists:roles,id'], - 'semester' => ['nullable', 'string', 'max:20'], - 'school_year' => ['nullable', 'string', 'max:20'], + 'user_id' => [$req, 'integer', 'min:1', 'exists:users,id'], + 'role_id' => [$req, 'integer', 'min:1', 'exists:roles,id'], + 'semester' => ['nullable', 'string', 'max:20'], + 'school_year'=> ['nullable', 'string', 'max:20'], 'updated_by' => ['nullable', 'integer'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/WhatsappGroupLink.php b/app/Models/WhatsappGroupLink.php index 5fea9dfb..2dcfe772 100644 --- a/app/Models/WhatsappGroupLink.php +++ b/app/Models/WhatsappGroupLink.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; class WhatsappGroupLink extends BaseModel { @@ -16,14 +17,13 @@ class WhatsappGroupLink extends BaseModel 'invite_link', 'active', ]; - public $timestamps = true; // requires created_at/updated_at protected $casts = [ 'class_section_id' => 'integer', - 'active' => 'boolean', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'active' => 'boolean', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -52,7 +52,7 @@ class WhatsappGroupLink extends BaseModel if ($allowNullSemester) { return $q->where(function (Builder $w) use ($sem) { $w->where('semester', $sem) - ->orWhereNull('semester'); + ->orWhereNull('semester'); }); } @@ -72,7 +72,7 @@ class WhatsappGroupLink extends BaseModel public function scopeHasInviteLink(Builder $q): Builder { return $q->whereNotNull('invite_link') - ->where('invite_link', '!=', ''); + ->where('invite_link', '!=', ''); } /* ============================================================ @@ -83,11 +83,11 @@ class WhatsappGroupLink extends BaseModel /** * Get the link for a specific section in a specific term. * - * @param int $sectionId Class/section code (not PK). - * @param string $year School year, e.g. "2025-2026". - * @param string $sem Semester, e.g. "Fall". - * @param bool $onlyActive If true, require active=1. - * @param bool $allowNullSemester If true, accept rows with semester IS NULL as well. + * @param int $sectionId Class/section code (not PK). + * @param string $year School year, e.g. "2025-2026". + * @param string $sem Semester, e.g. "Fall". + * @param bool $onlyActive If true, require active=1. + * @param bool $allowNullSemester If true, accept rows with semester IS NULL as well. */ public static function getLinkForSection( int $sectionId, @@ -114,8 +114,11 @@ class WhatsappGroupLink extends BaseModel /** * Get all links for a term. * - * @param bool|null $onlyActive true: active only, false: inactive only, null: both - * @param bool $allowNullSemester If true, include rows with semester IS NULL. + * @param string $year + * @param string $sem + * @param bool|null $onlyActive true: active only, false: inactive only, null: both + * @param bool $allowNullSemester If true, include rows with semester IS NULL. + * * @return array */ public static function getAllForTerm( @@ -154,16 +157,16 @@ class WhatsappGroupLink extends BaseModel ): self { $payload = [ 'class_section_name' => $sectionName, - 'invite_link' => trim($inviteLink), - 'active' => $active ? 1 : 0, + 'invite_link' => trim($inviteLink), + 'active' => $active ? 1 : 0, ]; // NOTE: semester is part of the uniqueness key like your legacy version. return static::query()->updateOrCreate( [ 'class_section_id' => $sectionId, - 'school_year' => trim($year), - 'semester' => trim($sem), + 'school_year' => trim($year), + 'semester' => trim($sem), ], $payload ); @@ -179,12 +182,12 @@ class WhatsappGroupLink extends BaseModel $req = $updating ? 'sometimes' : 'required'; return [ - 'class_section_id' => [$req, 'integer', 'min:1'], + 'class_section_id' => [$req, 'integer', 'min:1'], 'class_section_name' => [$req, 'string', 'max:255'], - 'school_year' => [$req, 'string', 'max:20'], - 'semester' => ['nullable', 'string', 'max:20'], - 'invite_link' => [$req, 'string', 'max:2000'], - 'active' => ['nullable', 'boolean'], + 'school_year' => [$req, 'string', 'max:20'], + 'semester' => ['nullable', 'string', 'max:20'], + 'invite_link' => [$req, 'string', 'max:2000'], + 'active' => ['nullable', 'boolean'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/WhatsappGroupMembership.php b/app/Models/WhatsappGroupMembership.php index 51ee49a5..6467f542 100644 --- a/app/Models/WhatsappGroupMembership.php +++ b/app/Models/WhatsappGroupMembership.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; class WhatsappGroupMembership extends BaseModel { @@ -20,17 +21,16 @@ class WhatsappGroupMembership extends BaseModel 'verified_by', 'verified_at', ]; - public $timestamps = true; // created_at, updated_at protected $casts = [ 'class_section_id' => 'integer', - 'subject_id' => 'integer', - 'is_member' => 'boolean', - 'verified_by' => 'integer', - 'verified_at' => 'datetime', - 'created_at' => 'datetime', - 'updated_at' => 'datetime', + 'subject_id' => 'integer', + 'is_member' => 'boolean', + 'verified_by' => 'integer', + 'verified_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; /* ============================================================ @@ -38,8 +38,7 @@ class WhatsappGroupMembership extends BaseModel * ============================================================ */ public const TYPE_PRIMARY = 'primary'; - - public const TYPE_SECOND = 'second'; + public const TYPE_SECOND = 'second'; public static function normType(string $type): string { @@ -54,7 +53,6 @@ class WhatsappGroupMembership extends BaseModel public function scopeForSections(Builder $q, array $sectionIds): Builder { $ids = array_values(array_unique(array_filter(array_map('intval', $sectionIds)))); - return empty($ids) ? $q->whereRaw('1=0') : $q->whereIn('class_section_id', $ids); } @@ -66,14 +64,13 @@ class WhatsappGroupMembership extends BaseModel public function scopeForSemester(Builder $q, string $sem): Builder { $sem = trim($sem); - return $sem === '' ? $q : $q->where('semester', $sem); } public function scopeForSubject(Builder $q, string $type, int $subjectId): Builder { return $q->where('subject_type', static::normType($type)) - ->where('subject_id', $subjectId); + ->where('subject_id', $subjectId); } /* ============================================================ @@ -88,12 +85,10 @@ class WhatsappGroupMembership extends BaseModel public static function getBySectionsAndTerm(array $sectionIds, string $year, string $sem): array { $ids = array_values(array_unique(array_filter(array_map('intval', $sectionIds)))); - if (empty($ids)) { - return []; - } + if (empty($ids)) return []; $year = trim($year); - $sem = trim($sem); + $sem = trim($sem); $q = static::query() ->forSections($ids) @@ -110,8 +105,8 @@ class WhatsappGroupMembership extends BaseModel $out = []; foreach ($rows as $m) { - $k = sprintf('%d:%s:%d', (int) $m->class_section_id, (string) $m->subject_type, (int) $m->subject_id); - if (! isset($out[$k])) { + $k = sprintf('%d:%s:%d', (int)$m->class_section_id, (string)$m->subject_type, (int)$m->subject_id); + if (!isset($out[$k])) { $out[$k] = $m->toArray(); } } @@ -139,15 +134,15 @@ class WhatsappGroupMembership extends BaseModel ): int { $type = static::normType($type); $year = trim($year); - $sem = trim($sem); + $sem = trim($sem); $payload = [ 'class_section_id' => $classSectionId, - 'school_year' => $year, - 'semester' => $sem, - 'subject_type' => $type, - 'subject_id' => $subjectId, - 'is_member' => $isMember ? 1 : 0, + 'school_year' => $year, + 'semester' => $sem, + 'subject_type' => $type, + 'subject_id' => $subjectId, + 'is_member' => $isMember ? 1 : 0, ]; if ($verifiedBy) { @@ -160,14 +155,13 @@ class WhatsappGroupMembership extends BaseModel $row = static::query()->updateOrCreate( [ 'class_section_id' => $classSectionId, - 'school_year' => $year, - 'semester' => $sem, - 'subject_type' => $type, - 'subject_id' => $subjectId, + 'school_year' => $year, + 'semester' => $sem, + 'subject_type' => $type, + 'subject_id' => $subjectId, ], $payload ); - return (int) $row->id; } @@ -183,7 +177,7 @@ class WhatsappGroupMembership extends BaseModel if ($existing) { // Keep semester from the existing row if present (legacy behavior). - if (! empty($existing->semester)) { + if (!empty($existing->semester)) { $payload['semester'] = (string) $existing->semester; } @@ -195,7 +189,6 @@ class WhatsappGroupMembership extends BaseModel // No existing row => create a new one (semester remains blank) $created = static::query()->create($payload); - return (int) $created->id; } @@ -210,13 +203,13 @@ class WhatsappGroupMembership extends BaseModel return [ 'class_section_id' => [$req, 'integer', 'min:1'], - 'school_year' => [$req, 'string', 'max:20'], - 'semester' => ['nullable', 'string', 'max:20'], - 'subject_type' => [$req, 'string', 'in:'.implode(',', [self::TYPE_PRIMARY, self::TYPE_SECOND])], - 'subject_id' => [$req, 'integer', 'min:1'], - 'is_member' => ['nullable', 'boolean'], - 'verified_by' => ['nullable', 'integer'], - 'verified_at' => ['nullable', 'date'], + 'school_year' => [$req, 'string', 'max:20'], + 'semester' => ['nullable', 'string', 'max:20'], + 'subject_type' => [$req, 'string', 'in:' . implode(',', [self::TYPE_PRIMARY, self::TYPE_SECOND])], + 'subject_id' => [$req, 'integer', 'min:1'], + 'is_member' => ['nullable', 'boolean'], + 'verified_by' => ['nullable', 'integer'], + 'verified_at' => ['nullable', 'date'], ]; } -} +} \ No newline at end of file diff --git a/app/Models/WhatsappInviteLog.php b/app/Models/WhatsappInviteLog.php index 76ae6705..0c966510 100644 --- a/app/Models/WhatsappInviteLog.php +++ b/app/Models/WhatsappInviteLog.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\BelongsTo; class WhatsappInviteLog extends BaseModel @@ -25,18 +26,17 @@ class WhatsappInviteLog extends BaseModel ]; protected $casts = [ - 'parent_id' => 'integer', + 'parent_id' => 'integer', 'class_section_id' => 'integer', - 'link_id' => 'integer', - 'sent_at' => 'datetime', + 'link_id' => 'integer', + 'sent_at' => 'datetime', ]; /* ============================================================ * Status constants (optional but helpful) * ============================================================ */ - public const STATUS_SENT = 'sent'; - + public const STATUS_SENT = 'sent'; public const STATUS_FAILED = 'failed'; /* ============================================================ @@ -103,13 +103,13 @@ class WhatsappInviteLog extends BaseModel ?int $linkId = null ): bool { static::query()->create([ - 'parent_id' => $parentId, - 'email' => $email, + 'parent_id' => $parentId, + 'email' => $email, 'class_section_id' => $classSectionId, - 'link_id' => $linkId, - 'status' => self::STATUS_SENT, - 'error_message' => null, - 'sent_at' => now(), + 'link_id' => $linkId, + 'status' => self::STATUS_SENT, + 'error_message' => null, + 'sent_at' => now(), ]); return true; @@ -126,13 +126,13 @@ class WhatsappInviteLog extends BaseModel ?int $linkId = null ): bool { static::query()->create([ - 'parent_id' => $parentId, - 'email' => $email, + 'parent_id' => $parentId, + 'email' => $email, 'class_section_id' => $classSectionId, - 'link_id' => $linkId, - 'status' => self::STATUS_FAILED, - 'error_message' => $error, - 'sent_at' => now(), + 'link_id' => $linkId, + 'status' => self::STATUS_FAILED, + 'error_message' => $error, + 'sent_at' => now(), ]); return true; @@ -167,13 +167,13 @@ class WhatsappInviteLog extends BaseModel $req = $updating ? 'sometimes' : 'required'; return [ - 'parent_id' => [$req, 'integer', 'min:1'], - 'email' => [$req, 'email', 'max:255'], - 'status' => [$req, 'string', 'max:20'], + 'parent_id' => [$req, 'integer', 'min:1'], + 'email' => [$req, 'email', 'max:255'], + 'status' => [$req, 'string', 'max:20'], 'class_section_id' => ['nullable', 'integer'], - 'link_id' => ['nullable', 'integer'], - 'error_message' => ['nullable', 'string', 'max:5000'], - 'sent_at' => ['nullable', 'date'], + 'link_id' => ['nullable', 'integer'], + 'error_message' => ['nullable', 'string', 'max:5000'], + 'sent_at' => ['nullable', 'date'], ]; } -} +} \ No newline at end of file diff --git a/app/Policies/NavItemPolicy.php b/app/Policies/NavItemPolicy.php index 44c57ee6..f6022037 100644 --- a/app/Policies/NavItemPolicy.php +++ b/app/Policies/NavItemPolicy.php @@ -2,6 +2,7 @@ namespace App\Policies; +use App\Models\NavItem; use App\Models\User; class NavItemPolicy @@ -9,7 +10,6 @@ class NavItemPolicy public function manage(User $user): bool { $roles = $user->roles()->pluck('roles.name')->map(fn ($name) => strtolower((string) $name))->toArray(); - return in_array('admin', $roles, true) || in_array('administrator', $roles, true); } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 742d555a..2b03f011 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,42 +2,42 @@ namespace App\Providers; -use App\Models\ClassProgressReport; -use App\Models\ClassSection; -use App\Models\IpAttempt; -use App\Models\LateSlipLog; -use App\Models\Message; -use App\Models\NavItem; -use App\Models\Preferences; -use App\Models\Setting; -use App\Models\Staff; -use App\Models\SupportRequest; -use App\Policies\ClassProgressReportPolicy; -use App\Policies\ClassSectionPolicy; -use App\Policies\IpAttemptPolicy; -use App\Policies\LateSlipLogPolicy; -use App\Policies\MessagePolicy; -use App\Policies\NavItemPolicy; -use App\Policies\PreferencesPolicy; -use App\Policies\SettingPolicy; -use App\Policies\StaffPolicy; -use App\Policies\SupportRequestPolicy; -use App\Services\ApplicationUrlService; -use App\Services\Attendance\AttendanceAutoPublishService; use App\Services\Attendance\AttendancePolicyService; use App\Services\Attendance\AttendanceRecordSyncService; use App\Services\Attendance\SemesterRangeService; use App\Services\Attendance\StudentAttendanceWriterService; use App\Services\Attendance\TeacherAttendanceSubmissionService; +use App\Services\Attendance\AttendanceAutoPublishService; use App\Services\AttendanceTracking\AttendanceMailerService; use App\Services\AttendanceTracking\DefaultAttendanceMailerService; use App\Services\Invoices\InvoiceConfigService; use App\Services\Invoices\InvoiceGradeService; use App\Services\Invoices\InvoiceTuitionService; use App\Services\Staff\StaffTimeOffLinkService; +use App\Models\NavItem; +use App\Models\ClassSection; +use App\Models\IpAttempt; +use App\Models\LateSlipLog; +use App\Models\Message; +use App\Models\Preferences; +use App\Models\Staff; +use App\Models\SupportRequest; +use App\Models\Setting; +use App\Models\ClassProgressReport; +use App\Policies\NavItemPolicy; +use App\Policies\ClassSectionPolicy; +use App\Policies\IpAttemptPolicy; +use App\Policies\LateSlipLogPolicy; +use App\Policies\MessagePolicy; +use App\Policies\PreferencesPolicy; +use App\Policies\StaffPolicy; +use App\Policies\SupportRequestPolicy; +use App\Policies\SettingPolicy; +use App\Policies\ClassProgressReportPolicy; +use Illuminate\Support\Facades\Gate; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Routing\Redirector; -use Illuminate\Support\Facades\Gate; +use App\Services\ApplicationUrlService; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -58,12 +58,10 @@ class AppServiceProvider extends ServiceProvider $this->app->singleton(InvoiceConfigService::class); $this->app->bind(InvoiceGradeService::class, function ($app) { $config = $app->make(InvoiceConfigService::class); - return new InvoiceGradeService($config->getGradeFee()); }); $this->app->bind(InvoiceTuitionService::class, function ($app) { $config = $app->make(InvoiceConfigService::class); - return new InvoiceTuitionService( $app->make(InvoiceGradeService::class), $config->getGradeFee(), diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 871de827..a7435f14 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -2,8 +2,8 @@ namespace App\Providers; -use App\Events\DeleteUnverifiedUser; use App\Events\WhatsappInvitesSend; +use App\Events\DeleteUnverifiedUser; use App\Listeners\AttendanceConsequenceListener; use App\Listeners\BelowSixtyEmailListener; use App\Listeners\DeleteUnverifiedUserListener; @@ -15,94 +15,94 @@ class EventServiceProvider extends ServiceProvider { protected $listen = [ 'attendance.follow_up' => [ - AttendanceConsequenceListener::class.'@followUp', + AttendanceConsequenceListener::class . '@followUp', ], 'attendance.final_warning' => [ - AttendanceConsequenceListener::class.'@finalWarning', + AttendanceConsequenceListener::class . '@finalWarning', ], 'attendance.dismissal' => [ - AttendanceConsequenceListener::class.'@dismissal', + AttendanceConsequenceListener::class . '@dismissal', ], 'below60.email' => [ BelowSixtyEmailListener::class, ], 'admissionUnderReview' => [ - SchoolEventListener::class.'@handleAdmissionUnderReview', + SchoolEventListener::class . '@handleAdmissionUnderReview', ], 'paymentPending' => [ - SchoolEventListener::class.'@handlePaymentPending', + SchoolEventListener::class . '@handlePaymentPending', ], 'studentEnrolled' => [ - SchoolEventListener::class.'@handleStudentEnrolled', + SchoolEventListener::class . '@handleStudentEnrolled', ], 'withdrawUnderReview' => [ - SchoolEventListener::class.'@handleWithdrawUnderReview', + SchoolEventListener::class . '@handleWithdrawUnderReview', ], 'refundPending' => [ - SchoolEventListener::class.'@handleRefundPending', + SchoolEventListener::class . '@handleRefundPending', ], 'withdrawn' => [ - SchoolEventListener::class.'@handleWithdrawn', + SchoolEventListener::class . '@handleWithdrawn', ], 'denied' => [ - SchoolEventListener::class.'@handleDenied', + SchoolEventListener::class . '@handleDenied', ], 'waitlist' => [ - SchoolEventListener::class.'@handleWaitlist', + SchoolEventListener::class . '@handleWaitlist', ], 'enrollmentStatusChanged' => [ - SchoolEventListener::class.'@handleEnrollmentStatusChanged', + SchoolEventListener::class . '@handleEnrollmentStatusChanged', ], 'paymentReceived' => [ - SchoolEventListener::class.'@handlePaymentReceived', + SchoolEventListener::class . '@handlePaymentReceived', ], 'extraCharge' => [ - SchoolEventListener::class.'@handleExtraCharge', + SchoolEventListener::class . '@handleExtraCharge', ], 'newAccountAdded' => [ - SchoolEventListener::class.'@handleNewAccountAdded', + SchoolEventListener::class . '@handleNewAccountAdded', ], 'studentRegistered' => [ - SchoolEventListener::class.'@handleStudentRegistered', + SchoolEventListener::class . '@handleStudentRegistered', ], 'delete_unverified_user' => [ - SchoolEventListener::class.'@handleDeleteUnverifiedUser', + SchoolEventListener::class . '@handleDeleteUnverifiedUser', ], 'userRegistered' => [ - SchoolEventListener::class.'@handleUserRegistered', + SchoolEventListener::class . '@handleUserRegistered', ], 'userProfileUpdated' => [ - SchoolEventListener::class.'@handleUserProfileUpdated', + SchoolEventListener::class . '@handleUserProfileUpdated', ], 'userDeactivated' => [ - SchoolEventListener::class.'@handleUserDeactivated', + SchoolEventListener::class . '@handleUserDeactivated', ], 'scoresPosted' => [ - SchoolEventListener::class.'@handleScoresPosted', + SchoolEventListener::class . '@handleScoresPosted', ], 'finalScoreReleased' => [ - SchoolEventListener::class.'@handleFinalScoreReleased', + SchoolEventListener::class . '@handleFinalScoreReleased', ], 'studentMarkedAbsent' => [ - SchoolEventListener::class.'@handleStudentMarkedAbsent', + SchoolEventListener::class . '@handleStudentMarkedAbsent', ], 'studentMarkedLate' => [ - SchoolEventListener::class.'@handleStudentMarkedLate', + SchoolEventListener::class . '@handleStudentMarkedLate', ], 'paymentMissed' => [ - SchoolEventListener::class.'@handlePaymentMissed', + SchoolEventListener::class . '@handlePaymentMissed', ], 'classScheduleUpdated' => [ - SchoolEventListener::class.'@handleClassScheduleUpdated', + SchoolEventListener::class . '@handleClassScheduleUpdated', ], 'newMessageReceived' => [ - SchoolEventListener::class.'@handleNewMessageReceived', + SchoolEventListener::class . '@handleNewMessageReceived', ], 'systemAnnouncementPosted' => [ - SchoolEventListener::class.'@handleSystemAnnouncementPosted', + SchoolEventListener::class . '@handleSystemAnnouncementPosted', ], 'customNotification' => [ - SchoolEventListener::class.'@handleCustomNotification', + SchoolEventListener::class . '@handleCustomNotification', ], DeleteUnverifiedUser::class => [ DeleteUnverifiedUserListener::class, diff --git a/app/Services/Admin/CompetitionWinners/CompetitionWinnersAdminService.php b/app/Services/Admin/CompetitionWinners/CompetitionWinnersAdminService.php index 7de223bf..f8358354 100644 --- a/app/Services/Admin/CompetitionWinners/CompetitionWinnersAdminService.php +++ b/app/Services/Admin/CompetitionWinners/CompetitionWinnersAdminService.php @@ -2,19 +2,17 @@ namespace App\Services\Admin\CompetitionWinners; -use App\Controllers\Admin\CompetitionWinnersController; use App\Models\ClassSection; use App\Models\Competition; use App\Models\CompetitionClassWinner; use App\Models\CompetitionScore; use App\Models\CompetitionWinner; use App\Models\Configuration; -use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; /** - * Administrative competition-winner workflows (ported from legacy {@see CompetitionWinnersController}). + * Administrative competition-winner workflows (ported from legacy {@see \App\Controllers\Admin\CompetitionWinnersController}). */ class CompetitionWinnersAdminService { @@ -182,7 +180,6 @@ class CompetitionWinnersAdminService if ($existing) { $existing->delete(); } - continue; } @@ -256,7 +253,7 @@ class CompetitionWinnersAdminService return $out; } - /** @return array{competitions: Collection, sectionMap: array} */ + /** @return array{competitions: \Illuminate\Support\Collection, sectionMap: array} */ public function indexData(): array { $competitions = Competition::query()->orderByDesc('id')->get(); diff --git a/app/Services/Admin/CompetitionWinners/CompetitionWinnersDomain.php b/app/Services/Admin/CompetitionWinners/CompetitionWinnersDomain.php index a895943e..f0a1922a 100644 --- a/app/Services/Admin/CompetitionWinners/CompetitionWinnersDomain.php +++ b/app/Services/Admin/CompetitionWinners/CompetitionWinnersDomain.php @@ -138,14 +138,12 @@ final class CompetitionWinnersDomain $override = $overrides[$classId] ?? null; if ($override !== null) { $map[$classId] = (int) $override; - continue; } $baseCount = $classCounts[$classId] ?? ($scoreCounts[$classId] ?? 0); if ($baseCount <= 0) { $map[$classId] = 0; - continue; } diff --git a/app/Services/Administrator/AdminNotificationSubjectService.php b/app/Services/Administrator/AdminNotificationSubjectService.php index 166a1ca4..473bd07c 100644 --- a/app/Services/Administrator/AdminNotificationSubjectService.php +++ b/app/Services/Administrator/AdminNotificationSubjectService.php @@ -9,7 +9,8 @@ class AdminNotificationSubjectService { public function __construct( protected AdminNotificationUserService $userService - ) {} + ) { + } public function subjectOptions(): array { @@ -30,7 +31,7 @@ class AdminNotificationSubjectService $assignedSubjects = []; $tableReady = DB::getSchemaBuilder()->hasTable('admin_notification_subjects'); - if ($tableReady && ! empty($admins)) { + if ($tableReady && !empty($admins)) { $adminIds = array_map('intval', array_column($admins, 'id')); $rows = AdminNotificationSubject::query() @@ -58,7 +59,7 @@ class AdminNotificationSubjectService public function save(array $posted): array { - if (! DB::getSchemaBuilder()->hasTable('admin_notification_subjects')) { + if (!DB::getSchemaBuilder()->hasTable('admin_notification_subjects')) { return [ 'success' => false, 'message' => 'Notification subject storage is missing. Run migrations first.', @@ -101,7 +102,7 @@ class AdminNotificationSubjectService if (is_array($subjectRaw)) { foreach ($subjectRaw as $key => $value) { $candidate = is_string($key) ? $key : $value; - if (! is_string($candidate)) { + if (!is_string($candidate)) { continue; } $candidate = trim($candidate); @@ -117,7 +118,7 @@ class AdminNotificationSubjectService $toDelete = array_values(array_diff($current, $selected)); $toInsert = array_values(array_diff($selected, $current)); - if (! empty($toDelete)) { + if (!empty($toDelete)) { AdminNotificationSubject::query() ->where('admin_id', $adminId) ->whereIn('subject', $toDelete) @@ -125,7 +126,7 @@ class AdminNotificationSubjectService $updates += count($toDelete); } - if (! empty($toInsert)) { + if (!empty($toInsert)) { $batch = []; foreach ($toInsert as $subject) { $batch[] = [ @@ -146,4 +147,4 @@ class AdminNotificationSubjectService 'status' => 200, ]; } -} +} \ No newline at end of file diff --git a/app/Services/Administrator/AdminNotificationUserService.php b/app/Services/Administrator/AdminNotificationUserService.php index 004216f8..4cda5390 100644 --- a/app/Services/Administrator/AdminNotificationUserService.php +++ b/app/Services/Administrator/AdminNotificationUserService.php @@ -37,7 +37,7 @@ class AdminNotificationUserService ->orderBy('u.lastname') ->orderBy('u.firstname') ->get() - ->map(fn ($r) => (array) $r) + ->map(fn($r) => (array) $r) ->all(); } -} +} \ No newline at end of file diff --git a/app/Services/Administrator/AdminPrintRecipientService.php b/app/Services/Administrator/AdminPrintRecipientService.php index 0dae8fae..da316754 100644 --- a/app/Services/Administrator/AdminPrintRecipientService.php +++ b/app/Services/Administrator/AdminPrintRecipientService.php @@ -9,7 +9,8 @@ class AdminPrintRecipientService { public function __construct( protected AdminNotificationUserService $userService - ) {} + ) { + } public function data(): array { @@ -17,7 +18,7 @@ class AdminPrintRecipientService $tableReady = DB::getSchemaBuilder()->hasTable('admin_notification_subjects'); $assigned = []; - if ($tableReady && ! empty($admins)) { + if ($tableReady && !empty($admins)) { $adminIds = array_map('intval', array_column($admins, 'id')); $rows = AdminNotificationSubject::query() @@ -43,7 +44,7 @@ class AdminPrintRecipientService public function save(array $posted): array { - if (! DB::getSchemaBuilder()->hasTable('admin_notification_subjects')) { + if (!DB::getSchemaBuilder()->hasTable('admin_notification_subjects')) { return [ 'success' => false, 'message' => 'Notification subject storage is missing. Run migrations first.', @@ -76,7 +77,7 @@ class AdminPrintRecipientService ->where('subject', 'print_requests') ->whereIn('admin_id', $adminIds) ->pluck('admin_id') - ->map(fn ($id) => (int) $id) + ->map(fn($id) => (int) $id) ->unique() ->values() ->all(); @@ -84,14 +85,14 @@ class AdminPrintRecipientService $toDelete = array_values(array_diff($current, $selected)); $toInsert = array_values(array_diff($selected, $current)); - if (! empty($toDelete)) { + if (!empty($toDelete)) { AdminNotificationSubject::query() ->where('subject', 'print_requests') ->whereIn('admin_id', $toDelete) ->delete(); } - if (! empty($toInsert)) { + if (!empty($toInsert)) { $batch = []; foreach ($toInsert as $adminId) { $batch[] = [ @@ -112,4 +113,4 @@ class AdminPrintRecipientService 'status' => 200, ]; } -} +} \ No newline at end of file diff --git a/app/Services/Administrator/AdministratorAbsenceService.php b/app/Services/Administrator/AdministratorAbsenceService.php index 87a92609..b15c51a0 100644 --- a/app/Services/Administrator/AdministratorAbsenceService.php +++ b/app/Services/Administrator/AdministratorAbsenceService.php @@ -2,12 +2,11 @@ namespace App\Services\Administrator; +use App\Services\ApplicationUrlService; +use App\Services\Staff\StaffTimeOffLinkService; use App\Models\StaffAttendance; use App\Models\User; -use App\Services\ApplicationUrlService; use App\Services\SemesterRangeService; -use App\Services\Staff\StaffTimeOffLinkService; -use Carbon\Carbon; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Mail; @@ -21,13 +20,14 @@ class AdministratorAbsenceService protected SemesterRangeService $semesterRangeService, protected StaffTimeOffLinkService $staffTimeOffLinkService, protected ApplicationUrlService $urls, - ) {} + ) { + } public function getAbsenceFormData(int $userId): array { $admin = $this->userModel->find($userId); $displayName = $admin - ? trim(($admin->firstname ?? '').' '.($admin->lastname ?? '')) + ? trim(($admin->firstname ?? '') . ' ' . ($admin->lastname ?? '')) : 'Administrator'; $semester = $this->shared->getSemester(); @@ -76,7 +76,7 @@ class AdministratorAbsenceService } $reasonBase = $reasonType !== '' ? strtolower($reasonType) : ''; - $reason = $reasonBase !== '' ? ($reasonBase.': '.$reasonText) : $reasonText; + $reason = $reasonBase !== '' ? ($reasonBase . ': ' . $reasonText) : $reasonText; $allowedSet = array_fill_keys($this->shared->allowedAbsenceDates(), true); @@ -97,15 +97,13 @@ class AdministratorAbsenceService } try { - $parsed = Carbon::createFromFormat('Y-m-d', $d); + $parsed = \Carbon\Carbon::createFromFormat('Y-m-d', $d); if ($parsed->format('Y-m-d') !== $d || empty($allowedSet[$d])) { $invalid[] = $d; - continue; } } catch (\Throwable) { $invalid[] = $d; - continue; } @@ -131,10 +129,10 @@ class AdministratorAbsenceService } } - if (! empty($invalid)) { + if (!empty($invalid)) { return [ 'success' => false, - 'message' => 'Invalid dates: '.implode(', ', $invalid), + 'message' => 'Invalid dates: ' . implode(', ', $invalid), 'status' => 422, ]; } @@ -152,7 +150,7 @@ class AdministratorAbsenceService return [ 'success' => true, - 'message' => $saved.' day(s) saved as absent.', + 'message' => $saved . ' day(s) saved as absent.', 'saved' => $saved, 'dates' => $savedDates, 'status' => 200, @@ -171,10 +169,10 @@ class AdministratorAbsenceService ): void { try { $user = $this->userModel->find($userId); - $fullName = trim(($user->firstname ?? '').' '.($user->lastname ?? '')) ?: 'Administrator'; + $fullName = trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? '')) ?: 'Administrator'; $userEmail = $user->email ?? ''; $role = $roleName ?: 'admin'; - $dateList = ! empty($savedDates) ? implode(', ', $savedDates) : implode(', ', $dates); + $dateList = !empty($savedDates) ? implode(', ', $savedDates) : implode(', ', $dates); $subject = sprintf( 'TimeOff Request: %s (%s) — %s', @@ -186,20 +184,20 @@ class AdministratorAbsenceService $submittedAt = now()->toDateTimeString(); $body = '
' - .'

New TimeOff Request

' - .'

A staff time-off request was submitted from the administrator portal.

' - .'' - .'' - .'' - .'' - .'' - .'' - .'' - .'' - .'' - .'' - .'
Name'.e($fullName).'
Email'.e($userEmail).'
Role'.e((string) $role).'
Semester'.e($semester).'
School Year'.e($schoolYear).'
Reason Type'.e($reasonType ?: '-').'
Reason'.e($reasonText).'
Dates'.e($dateList ?: '-').'
Submitted At'.e($submittedAt).'
' - .'
'; + . '

New TimeOff Request

' + . '

A staff time-off request was submitted from the administrator portal.

' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '
Name' . e($fullName) . '
Email' . e($userEmail) . '
Role' . e((string) $role) . '
Semester' . e($semester) . '
School Year' . e($schoolYear) . '
Reason Type' . e($reasonType ?: '-') . '
Reason' . e($reasonText) . '
Dates' . e($dateList ?: '-') . '
Submitted At' . e($submittedAt) . '
' + . ''; $token = $this->staffTimeOffLinkService->createToken([ 'uid' => $userId, @@ -215,9 +213,9 @@ class AdministratorAbsenceService $notifyUrl = $this->urls->timeoffNotifyUrl($token); - $body .= '

Click Send confirmation email to ' - .e($fullName) - .' so the staff member is notified automatically. This link expires in 14 days.

'; + $body .= '

Click Send confirmation email to ' + . e($fullName) + . ' so the staff member is notified automatically. This link expires in 14 days.

'; $principalEmail = env('PRINCIPAL_EMAIL', 'principal@alrahmaisgl.org'); @@ -225,7 +223,7 @@ class AdministratorAbsenceService $message->to($principalEmail)->subject($subject); }); } catch (\Throwable $e) { - Log::error('Failed to send TimeOff email (admin): '.$e->getMessage()); + Log::error('Failed to send TimeOff email (admin): ' . $e->getMessage()); } } } diff --git a/app/Services/Administrator/AdministratorDashboardService.php b/app/Services/Administrator/AdministratorDashboardService.php index 4db14733..42261eaa 100644 --- a/app/Services/Administrator/AdministratorDashboardService.php +++ b/app/Services/Administrator/AdministratorDashboardService.php @@ -7,7 +7,8 @@ class AdministratorDashboardService public function __construct( protected AdministratorMetricsService $metricsService, protected AdministratorUserSearchService $userSearchService, - ) {} + ) { + } public function metrics(): array { @@ -18,4 +19,4 @@ class AdministratorDashboardService { return $this->userSearchService->search($query); } -} +} \ No newline at end of file diff --git a/app/Services/Administrator/AdministratorEnrollmentEventService.php b/app/Services/Administrator/AdministratorEnrollmentEventService.php index 4439f2db..957d4029 100644 --- a/app/Services/Administrator/AdministratorEnrollmentEventService.php +++ b/app/Services/Administrator/AdministratorEnrollmentEventService.php @@ -10,7 +10,8 @@ class AdministratorEnrollmentEventService { public function __construct( private ApplicationUrlService $urls, - ) {} + ) { + } public function dispatchGroupedEvents( array $groupsByParentStatus, @@ -44,7 +45,7 @@ class AdministratorEnrollmentEventService ->first(); foreach ($byStatus as $status => $studentsArr) { - if (! isset($eventMap[$status])) { + if (!isset($eventMap[$status])) { continue; } @@ -76,4 +77,4 @@ class AdministratorEnrollmentEventService } } } -} +} \ No newline at end of file diff --git a/app/Services/Administrator/AdministratorEnrollmentQueryService.php b/app/Services/Administrator/AdministratorEnrollmentQueryService.php index 2fe70265..51c0d4e7 100644 --- a/app/Services/Administrator/AdministratorEnrollmentQueryService.php +++ b/app/Services/Administrator/AdministratorEnrollmentQueryService.php @@ -17,7 +17,8 @@ class AdministratorEnrollmentQueryService protected StudentClass $studentClassModel, protected Enrollment $enrollmentModel, protected ClassSection $classSectionModel, - ) {} + ) { + } public function enrollmentWithdrawalData(?string $selectedYear = null): array { @@ -58,7 +59,7 @@ class AdministratorEnrollmentQueryService $s['student_id'] = $studentId; $s['removed_previous_year'] = isset($removedPriorIds[$studentId]) ? 'Yes' : 'No'; - if (empty($s['parent_id']) && ! empty($s['secondparent_user_id'])) { + if (empty($s['parent_id']) && !empty($s['secondparent_user_id'])) { $s['parent_id'] = (int) $s['secondparent_user_id']; } else { $s['parent_id'] = (int) ($s['parent_id'] ?? 0); @@ -67,14 +68,14 @@ class AdministratorEnrollmentQueryService $pf = trim((string) ($s['parent_firstname'] ?? '')); $pl = trim((string) ($s['parent_lastname'] ?? '')); - if ($pf === '' && $pl === '' && ! empty($s['parent_fullname'])) { + if ($pf === '' && $pl === '' && !empty($s['parent_fullname'])) { $parts = preg_split('/\s+/', trim((string) $s['parent_fullname']), 2); $pf = $parts[0] ?? ''; $pl = $parts[1] ?? ''; } - $s['parent_label'] = trim($pf.' '.$pl) ?: 'Unknown Parent'; - $s['parent_sort'] = trim(($pl !== '' ? $pl : $pf).' '.$pf) ?: 'ZZZ Unknown Parent'; + $s['parent_label'] = trim($pf . ' ' . $pl) ?: 'Unknown Parent'; + $s['parent_sort'] = trim(($pl !== '' ? $pl : $pf) . ' ' . $pf) ?: 'ZZZ Unknown Parent'; $s['is_new'] = (int) ($s['is_new'] ?? 0); $s['new_student'] = $s['is_new'] === 1 ? 'Yes' : 'No'; @@ -83,7 +84,7 @@ class AdministratorEnrollmentQueryService ? $this->enrollmentModel->getEnrollmentStatus($studentId, $selectedYear) : null; - if (! empty($statusForYear)) { + if (!empty($statusForYear)) { $s['enrollment_status'] = $statusForYear; } elseif (($s['admission_status'] ?? null) === 'denied') { $s['enrollment_status'] = 'denied'; @@ -95,7 +96,7 @@ class AdministratorEnrollmentQueryService $s['class_section'] = $className ?: 'Class not Assigned'; - $s['registration_date_order'] = ! empty($s['registration_date']) + $s['registration_date_order'] = !empty($s['registration_date']) ? Carbon::parse($s['registration_date'])->format('Y-m-d') : ''; } @@ -171,10 +172,10 @@ class AdministratorEnrollmentQueryService $r['is_new'] = (int) ($r['is_new'] ?? 0); $r['new_student'] = $r['is_new'] === 1 ? 'Yes' : 'No'; - $r['modalIdContact'] = 'contact_'.$studentId; + $r['modalIdContact'] = 'contact_' . $studentId; $r['enrollment_status'] = $enrollmentStatus; - if (! empty($r['registration_date'])) { + if (!empty($r['registration_date'])) { try { $r['registration_date'] = Carbon::parse($r['registration_date'])->format('Y-m-d'); } catch (\Throwable) { @@ -190,4 +191,4 @@ class AdministratorEnrollmentQueryService 'total_new' => count($newStudents), ]; } -} +} \ No newline at end of file diff --git a/app/Services/Administrator/AdministratorEnrollmentRefundService.php b/app/Services/Administrator/AdministratorEnrollmentRefundService.php index 6fc72392..9d36a60c 100644 --- a/app/Services/Administrator/AdministratorEnrollmentRefundService.php +++ b/app/Services/Administrator/AdministratorEnrollmentRefundService.php @@ -11,7 +11,8 @@ class AdministratorEnrollmentRefundService { public function __construct( protected FeeCalculationService $feeCalculationService - ) {} + ) { + } public function processRefunds(array $parentIds, string $schoolYear, int $editorUserId): array { @@ -35,9 +36,8 @@ class AdministratorEnrollmentRefundService ->latest('created_at') ->first(); - if (! $invoice) { + if (!$invoice) { $errors[] = "No invoice found for parent ID {$pid} (for refund calc)."; - continue; } diff --git a/app/Services/Administrator/AdministratorEnrollmentService.php b/app/Services/Administrator/AdministratorEnrollmentService.php index 89d09bb7..f2c2068f 100644 --- a/app/Services/Administrator/AdministratorEnrollmentService.php +++ b/app/Services/Administrator/AdministratorEnrollmentService.php @@ -7,7 +7,8 @@ class AdministratorEnrollmentService public function __construct( protected AdministratorEnrollmentQueryService $queryService, protected AdministratorEnrollmentStatusService $statusService, - ) {} + ) { + } public function enrollmentWithdrawalData(?string $selectedYear = null): array { diff --git a/app/Services/Administrator/AdministratorEnrollmentStatusService.php b/app/Services/Administrator/AdministratorEnrollmentStatusService.php index 90a1d5cb..cda49b10 100644 --- a/app/Services/Administrator/AdministratorEnrollmentStatusService.php +++ b/app/Services/Administrator/AdministratorEnrollmentStatusService.php @@ -15,7 +15,8 @@ class AdministratorEnrollmentStatusService protected User $userModel, protected AdministratorEnrollmentRefundService $refundService, protected AdministratorEnrollmentEventService $eventService, - ) {} + ) { + } public function updateStatuses(array $enrollmentStatuses, int $editorUserId): array { @@ -52,9 +53,8 @@ class AdministratorEnrollmentStatusService foreach ($enrollmentStatuses as $studentId => $newEnrollmentStatus) { $studentId = (int) $studentId; - if (! in_array($newEnrollmentStatus, $validStatuses, true)) { + if (!in_array($newEnrollmentStatus, $validStatuses, true)) { $errors[] = "Invalid enrollment status '{$newEnrollmentStatus}' for student ID {$studentId}."; - continue; } @@ -68,7 +68,7 @@ class AdministratorEnrollmentStatusService $refundParents ); - if (! $result['success']) { + if (!$result['success']) { $errors[] = $result['message']; } } @@ -99,7 +99,7 @@ class AdministratorEnrollmentStatusService ]; } catch (\Throwable $e) { DB::rollBack(); - Log::error('Enrollment withdrawal error: '.$e->getMessage()); + Log::error('Enrollment withdrawal error: ' . $e->getMessage()); return [ 'success' => false, @@ -129,7 +129,7 @@ class AdministratorEnrollmentStatusService ->where('school_year', $schoolYear) ->first(); - if (! $enrollmentRow) { + if (!$enrollmentRow) { return $this->createEnrollmentRow( $studentId, $newEnrollmentStatus, @@ -145,7 +145,7 @@ class AdministratorEnrollmentStatusService $oldStatus = $enrollmentRow->enrollment_status ?? null; $parentId = (int) ($enrollmentRow->parent_id ?? 0); - if (! $parentId) { + if (!$parentId) { return [ 'success' => false, 'message' => "No parent ID found for student ID {$studentId}.", @@ -165,7 +165,7 @@ class AdministratorEnrollmentStatusService 'updated_at' => now(), ]); - if (! $updated) { + if (!$updated) { return [ 'success' => false, 'message' => "Failed to update enrollment for student ID {$studentId}.", @@ -201,7 +201,7 @@ class AdministratorEnrollmentStatusService $stu = is_array($stu) ? $stu : ($stu?->toArray() ?? []); $parentId = (int) ($stu['parent_id'] ?? ($stu['secondparent_user_id'] ?? 0)); - if (! $parentId) { + if (!$parentId) { return [ 'success' => false, 'message' => "No parent ID found for student ID {$studentId}.", @@ -223,7 +223,7 @@ class AdministratorEnrollmentStatusService 'updated_at' => now(), ]); - if (! $ok) { + if (!$ok) { return [ 'success' => false, 'message' => "Failed to create enrollment for student ID {$studentId}.", @@ -250,7 +250,7 @@ class AdministratorEnrollmentStatusService $studentRow = $this->studentModel->find($studentId); $studentData = is_array($studentRow) ? $studentRow : ($studentRow?->toArray() ?? []); - return trim(($studentData['firstname'] ?? '').' '.($studentData['lastname'] ?? '')) + return trim(($studentData['firstname'] ?? '') . ' ' . ($studentData['lastname'] ?? '')) ?: "Student #{$studentId}"; } diff --git a/app/Services/Administrator/AdministratorMetricsService.php b/app/Services/Administrator/AdministratorMetricsService.php index cfa99e28..7675461d 100644 --- a/app/Services/Administrator/AdministratorMetricsService.php +++ b/app/Services/Administrator/AdministratorMetricsService.php @@ -12,7 +12,8 @@ class AdministratorMetricsService protected AdministratorSharedService $shared, protected User $userModel, protected LoginActivity $loginActivityModel, - ) {} + ) { + } public function metrics(): array { @@ -69,4 +70,4 @@ class AdministratorMetricsService ], ]; } -} +} \ No newline at end of file diff --git a/app/Services/Administrator/AdministratorNotificationService.php b/app/Services/Administrator/AdministratorNotificationService.php index 42494180..acfd591e 100644 --- a/app/Services/Administrator/AdministratorNotificationService.php +++ b/app/Services/Administrator/AdministratorNotificationService.php @@ -7,7 +7,8 @@ class AdministratorNotificationService public function __construct( protected AdminNotificationSubjectService $subjectService, protected AdminPrintRecipientService $printRecipientService, - ) {} + ) { + } public function notificationsAlertsData(): array { @@ -28,4 +29,4 @@ class AdministratorNotificationService { return $this->printRecipientService->save($posted); } -} +} \ No newline at end of file diff --git a/app/Services/Administrator/AdministratorSharedService.php b/app/Services/Administrator/AdministratorSharedService.php index f615046d..25d1f565 100644 --- a/app/Services/Administrator/AdministratorSharedService.php +++ b/app/Services/Administrator/AdministratorSharedService.php @@ -9,7 +9,8 @@ class AdministratorSharedService { public function __construct( protected Configuration $configuration - ) {} + ) { + } public function getSemester(?string $override = null): string { @@ -34,7 +35,7 @@ class AdministratorSharedService } if (preg_match('/^(\d{4})\s*-\s*(\d{4})$/', $schoolYear, $m)) { - return ((int) $m[1] - 1).'-'.((int) $m[2] - 1); + return ((int) $m[1] - 1) . '-' . ((int) $m[2] - 1); } if (preg_match('/^(\d{4})\s*-\s*(\d{2})$/', $schoolYear, $m)) { @@ -43,7 +44,6 @@ class AdministratorSharedService if ($end < 0) { $end += 100; } - return sprintf('%04d-%02d', $start, $end); } @@ -126,7 +126,7 @@ class AdministratorSharedService public function countUniqueEntities($rows): int { - if (! is_iterable($rows)) { + if (!is_iterable($rows)) { return 0; } diff --git a/app/Services/Administrator/AdministratorTeacherSubmissionService.php b/app/Services/Administrator/AdministratorTeacherSubmissionService.php index c49ba590..5ccc2af9 100644 --- a/app/Services/Administrator/AdministratorTeacherSubmissionService.php +++ b/app/Services/Administrator/AdministratorTeacherSubmissionService.php @@ -9,7 +9,8 @@ class AdministratorTeacherSubmissionService public function __construct( protected TeacherSubmissionReportService $reportService, protected TeacherSubmissionNotificationService $notificationService, - ) {} + ) { + } public function report(array $filters = []): array { diff --git a/app/Services/Administrator/AdministratorUserSearchService.php b/app/Services/Administrator/AdministratorUserSearchService.php index 06a31c50..507bc29d 100644 --- a/app/Services/Administrator/AdministratorUserSearchService.php +++ b/app/Services/Administrator/AdministratorUserSearchService.php @@ -38,23 +38,23 @@ class AdministratorUserSearchService $v[] = sprintf('(%s)-%s-%s', substr($digits, 0, 3), substr($digits, 3, 3), substr($digits, 6)); $v[] = sprintf('%s-%s-%s', substr($digits, 0, 3), substr($digits, 3, 3), substr($digits, 6)); $v[] = sprintf('%s %s %s', substr($digits, 0, 3), substr($digits, 3, 3), substr($digits, 6)); - $v[] = '1'.$digits; - $v[] = '+1'.$digits; - $v[] = '+1 '.sprintf('(%s) %s-%s', substr($digits, 0, 3), substr($digits, 3, 3), substr($digits, 6)); - $v[] = '+1-'.sprintf('%s-%s-%s', substr($digits, 0, 3), substr($digits, 3, 3), substr($digits, 6)); + $v[] = '1' . $digits; + $v[] = '+1' . $digits; + $v[] = '+1 ' . sprintf('(%s) %s-%s', substr($digits, 0, 3), substr($digits, 3, 3), substr($digits, 6)); + $v[] = '+1-' . sprintf('%s-%s-%s', substr($digits, 0, 3), substr($digits, 3, 3), substr($digits, 6)); } elseif (strlen($digits) === 11 && str_starts_with($digits, '1')) { $ten = substr($digits, 1); $v[] = $ten; $v[] = sprintf('(%s)-%s-%s', substr($ten, 0, 3), substr($ten, 3, 3), substr($ten, 6)); $v[] = sprintf('%s-%s-%s', substr($ten, 0, 3), substr($ten, 3, 3), substr($ten, 6)); $v[] = sprintf('%s %s %s', substr($ten, 0, 3), substr($ten, 3, 3), substr($ten, 6)); - $v[] = '+1'.$ten; - $v[] = '+1 '.sprintf('(%s) %s-%s', substr($ten, 0, 3), substr($ten, 3, 3), substr($ten, 6)); - $v[] = '+1-'.sprintf('%s-%s-%s', substr($ten, 0, 3), substr($ten, 3, 3), substr($ten, 6)); + $v[] = '+1' . $ten; + $v[] = '+1 ' . sprintf('(%s) %s-%s', substr($ten, 0, 3), substr($ten, 3, 3), substr($ten, 6)); + $v[] = '+1-' . sprintf('%s-%s-%s', substr($ten, 0, 3), substr($ten, 3, 3), substr($ten, 6)); } } - if (! empty($v)) { + if (!empty($v)) { $phoneMap[$t] = array_values(array_unique($v)); } } @@ -63,13 +63,13 @@ class AdministratorUserSearchService foreach ($tokens as $t) { $qb->where(function ($sub) use ($columns, $phoneCols, $phoneMap, $t) { foreach ($columns as $col) { - $sub->orWhere($col, 'like', '%'.$t.'%'); + $sub->orWhere($col, 'like', '%' . $t . '%'); } - if (! empty($phoneMap[$t]) && ! empty($phoneCols)) { + if (!empty($phoneMap[$t]) && !empty($phoneCols)) { foreach ($phoneMap[$t] as $pv) { foreach ($phoneCols as $pcol) { - $sub->orWhere($pcol, 'like', '%'.$pv.'%'); + $sub->orWhere($pcol, 'like', '%' . $pv . '%'); } } } @@ -82,12 +82,12 @@ class AdministratorUserSearchService $uQB = DB::table('users') ->select('id', 'firstname', 'lastname', 'email', 'cellphone', 'school_id', 'city', 'state', 'school_year', 'semester'); $applyMultiTokenLike($uQB, ['firstname', 'lastname', 'email', 'cellphone', 'school_id', 'city', 'state'], $tokens, ['cellphone']); - $users = $uQB->limit(150)->get()->map(fn ($r) => (array) $r)->all(); + $users = $uQB->limit(150)->get()->map(fn($r) => (array) $r)->all(); $sQB = DB::table('students') ->select('id', 'parent_id', 'school_id', 'firstname', 'lastname', 'dob', 'gender', 'school_year', 'semester', 'rfid_tag'); $applyMultiTokenLike($sQB, ['firstname', 'lastname', 'school_id', 'rfid_tag', 'dob', 'gender'], $tokens); - $students = $sQB->limit(150)->get()->map(fn ($r) => (array) $r)->all(); + $students = $sQB->limit(150)->get()->map(fn($r) => (array) $r)->all(); $pQB = DB::table('parents') ->select('id', 'firstparent_id', 'secondparent_firstname', 'secondparent_lastname', 'secondparent_email', 'secondparent_phone', 'school_year', 'semester'); @@ -99,17 +99,17 @@ class AdministratorUserSearchService } } - $parents = $pQB->limit(150)->get()->map(fn ($r) => (array) $r)->all(); + $parents = $pQB->limit(150)->get()->map(fn($r) => (array) $r)->all(); $stQB = DB::table('staff') ->select('id', 'user_id', 'firstname', 'lastname', 'email', 'phone', 'role_name', 'school_year', 'active_role'); $applyMultiTokenLike($stQB, ['firstname', 'lastname', 'email', 'role_name', 'phone'], $tokens, ['phone']); - $staff = $stQB->limit(150)->get()->map(fn ($r) => (array) $r)->all(); + $staff = $stQB->limit(150)->get()->map(fn($r) => (array) $r)->all(); $ecQB = DB::table('emergency_contacts') ->select('id', 'parent_id', 'emergency_contact_name', 'relation', 'cellphone', 'email', 'school_year', 'semester'); $applyMultiTokenLike($ecQB, ['emergency_contact_name', 'relation', 'email', 'cellphone'], $tokens, ['cellphone']); - $emergency = $ecQB->limit(150)->get()->map(fn ($r) => (array) $r)->all(); + $emergency = $ecQB->limit(150)->get()->map(fn($r) => (array) $r)->all(); return [ 'query' => $q, @@ -125,4 +125,4 @@ class AdministratorUserSearchService 'total_found' => count($users) + count($students) + count($parents) + count($staff) + count($emergency), ]; } -} +} \ No newline at end of file diff --git a/app/Services/Administrator/TeacherSubmissionNotificationService.php b/app/Services/Administrator/TeacherSubmissionNotificationService.php index debe4769..171fab54 100644 --- a/app/Services/Administrator/TeacherSubmissionNotificationService.php +++ b/app/Services/Administrator/TeacherSubmissionNotificationService.php @@ -3,10 +3,10 @@ namespace App\Services\Administrator; use App\Mail\TeacherSubmissionReminderMail; +use App\Services\ApplicationUrlService; use App\Models\ClassSection; use App\Models\TeacherSubmissionNotificationHistory; use App\Models\User; -use App\Services\ApplicationUrlService; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Mail; @@ -17,12 +17,13 @@ class TeacherSubmissionNotificationService protected AdministratorSharedService $shared, protected TeacherSubmissionSupportService $support, protected ApplicationUrlService $urls, - ) {} + ) { + } public function send(Request $request, int $adminId): array { $notify = $request->input('notify'); - if (! is_array($notify)) { + if (!is_array($notify)) { return [ 'success' => false, 'message' => 'Select at least one teacher to notify.', @@ -59,7 +60,7 @@ class TeacherSubmissionNotificationService ->keyBy('id'); $adminUser = User::find($adminId); - $adminName = trim(($adminUser->firstname ?? '').' '.($adminUser->lastname ?? '')) ?: 'Administrator'; + $adminName = trim(($adminUser->firstname ?? '') . ' ' . ($adminUser->lastname ?? '')) ?: 'Administrator'; $scoreUrl = $this->urls->docsHomeUrl(); $sentCount = 0; @@ -71,30 +72,30 @@ class TeacherSubmissionNotificationService $teacher = $teachers->get($teacherId); $sectionName = $classSections->get($classSectionId)?->class_section_name ?? "Section {$classSectionId}"; - $teacherName = trim(($teacher->firstname ?? '').' '.($teacher->lastname ?? '')) ?: 'Teacher'; + $teacherName = trim(($teacher->firstname ?? '') . ' ' . ($teacher->lastname ?? '')) ?: 'Teacher'; $missingItems = $this->resolveMissingItems($missingItemsPayload, $classSectionId, $teacherId); - $missingNote = ! empty($missingItems) - ? '

Outstanding items: '.e($this->support->formatMissingItemsText($missingItems)).'.

' + $missingNote = !empty($missingItems) + ? '

Outstanding items: ' . e($this->support->formatMissingItemsText($missingItems)) . '.

' : '

Our records show no outstanding submissions for this section, but please verify if anything still needs attention.

'; $subject = "Reminder: Complete submissions for {$sectionName}"; $body = "

Dear {$teacherName},

" - ."

Administration is gently reminding you to wrap up any remaining score submissions and/or comments for {$sectionName}.

" - .$missingNote - ."

Visit Teacher Score Submission to address any remaining items.

" - ."

Thank you,
{$adminName}

"; + . "

Administration is gently reminding you to wrap up any remaining score submissions and/or comments for {$sectionName}.

" + . $missingNote + . "

Visit Teacher Score Submission to address any remaining items.

" + . "

Thank you,
{$adminName}

"; $email = $teacher->email ?? ''; $status = 'failed'; - if (! empty($email) && filter_var($email, FILTER_VALIDATE_EMAIL)) { + if (!empty($email) && filter_var($email, FILTER_VALIDATE_EMAIL)) { try { Mail::to($email)->send(new TeacherSubmissionReminderMail($subject, $body)); $status = 'sent'; } catch (\Throwable $e) { - Log::error('Teacher submission notification failed: '.$e->getMessage()); + Log::error('Teacher submission notification failed: ' . $e->getMessage()); } } @@ -119,15 +120,15 @@ class TeacherSubmissionNotificationService $parts = []; if ($sentCount > 0) { - $parts[] = $sentCount.' reminder'.($sentCount === 1 ? '' : 's').' sent'; + $parts[] = $sentCount . ' reminder' . ($sentCount === 1 ? '' : 's') . ' sent'; } if ($failCount > 0) { - $parts[] = $failCount.' reminder'.($failCount === 1 ? '' : 's').' failed'; + $parts[] = $failCount . ' reminder' . ($failCount === 1 ? '' : 's') . ' failed'; } return [ 'success' => $failCount === 0, - 'message' => ! empty($parts) ? implode(' and ', $parts) : 'No notifications were sent.', + 'message' => !empty($parts) ? implode(' and ', $parts) : 'No notifications were sent.', 'sent' => $sentCount, 'failed' => $failCount, 'status' => $failCount === 0 ? 200 : 207, @@ -163,7 +164,7 @@ class TeacherSubmissionNotificationService foreach ($notify as $sectionIdRaw => $teachers) { $sectionId = (int) $sectionIdRaw; - if ($sectionId <= 0 || ! is_array($teachers)) { + if ($sectionId <= 0 || !is_array($teachers)) { continue; } @@ -196,7 +197,7 @@ class TeacherSubmissionNotificationService protected function resolveMissingItems($payload, int $classSectionId, int $teacherId): array { - if (! is_array($payload)) { + if (!is_array($payload)) { return []; } diff --git a/app/Services/Administrator/TeacherSubmissionReportService.php b/app/Services/Administrator/TeacherSubmissionReportService.php index 898004ba..9bf11f26 100644 --- a/app/Services/Administrator/TeacherSubmissionReportService.php +++ b/app/Services/Administrator/TeacherSubmissionReportService.php @@ -14,7 +14,8 @@ class TeacherSubmissionReportService public function __construct( protected AdministratorSharedService $shared, protected TeacherSubmissionSupportService $support - ) {} + ) { + } public function report(array $filters = []): array { @@ -55,14 +56,14 @@ class TeacherSubmissionReportService default => $roleKey !== '' ? ucfirst($roleKey) : 'Teacher', }; - $teacherFullName = trim(($assignment['firstname'] ?? '').' '.($assignment['lastname'] ?? '')); + $teacherFullName = trim(($assignment['firstname'] ?? '') . ' ' . ($assignment['lastname'] ?? '')); $teacherId = (int) ($assignment['teacher_id'] ?? 0); if ($teacherFullName === '' || $teacherId <= 0) { continue; } - if (! isset($teachersBySection[$sectionId])) { + if (!isset($teachersBySection[$sectionId])) { $teachersBySection[$sectionId] = [ 'class_section' => $assignment['class_section_name'] ?? "Section {$sectionId}", 'teachers' => [], @@ -112,7 +113,7 @@ class TeacherSubmissionReportService foreach ($scoreRecords as $score) { $sid = (int) ($score->student_id ?? 0); - if ($sid <= 0 || ($expected > 0 && ! in_array($sid, $studentIds, true))) { + if ($sid <= 0 || ($expected > 0 && !in_array($sid, $studentIds, true))) { continue; } @@ -128,7 +129,7 @@ class TeacherSubmissionReportService $midtermCommentStudents = []; $ptapCommentStudents = []; - if (! empty($studentIds)) { + if (!empty($studentIds)) { $comments = ScoreComment::query() ->select('student_id', 'score_type', 'comment') ->whereIn('student_id', $studentIds) @@ -176,7 +177,7 @@ class TeacherSubmissionReportService ); foreach ($teacherList as $teacherEntry) { - if (! empty($teacherEntry['id'])) { + if (!empty($teacherEntry['id'])) { $allTeacherIds[] = $teacherEntry['id']; } } @@ -263,7 +264,7 @@ class TeacherSubmissionReportService continue; } - $adminName = trim(($record->firstname ?? '').' '.($record->lastname ?? '')); + $adminName = trim(($record->firstname ?? '') . ' ' . ($record->lastname ?? '')); if ($adminName === '') { $adminName = 'Administrator'; } diff --git a/app/Services/Administrator/TeacherSubmissionSupportService.php b/app/Services/Administrator/TeacherSubmissionSupportService.php index 1ea89741..a2d242c1 100644 --- a/app/Services/Administrator/TeacherSubmissionSupportService.php +++ b/app/Services/Administrator/TeacherSubmissionSupportService.php @@ -54,7 +54,7 @@ class TeacherSubmissionSupportService $items = []; foreach ($statusMap as $key => $status) { - if (! (bool) ($status['completed'] ?? true) && isset($labels[$key])) { + if (!(bool) ($status['completed'] ?? true) && isset($labels[$key])) { $items[] = $labels[$key]; } } @@ -80,7 +80,7 @@ class TeacherSubmissionSupportService return mb_strlen($text) <= $limit ? $text - : mb_substr($text, 0, $limit).'…'; + : mb_substr($text, 0, $limit) . '…'; } public function parseMissingItemsPayload($payload): array @@ -103,7 +103,7 @@ class TeacherSubmissionSupportService } $decoded = json_decode(base64_decode($payload, true) ?: '', true); - if (! is_array($decoded)) { + if (!is_array($decoded)) { return []; } @@ -130,11 +130,10 @@ class TeacherSubmissionSupportService return $items[0]; } if ($count === 2) { - return $items[0].' and '.$items[1]; + return $items[0] . ' and ' . $items[1]; } $last = array_pop($items); - - return implode(', ', $items).' and '.$last; + return implode(', ', $items) . ' and ' . $last; } } diff --git a/app/Services/Administrator/Trophy/TrophyReportService.php b/app/Services/Administrator/Trophy/TrophyReportService.php index f3646853..84bb2825 100644 --- a/app/Services/Administrator/Trophy/TrophyReportService.php +++ b/app/Services/Administrator/Trophy/TrophyReportService.php @@ -305,7 +305,7 @@ class TrophyReportService } /** - * @return Collection> + * @return \Illuminate\Support\Collection> */ private function studentRows(string $schoolYear): Collection { @@ -393,7 +393,7 @@ class TrophyReportService } /** - * @param Collection> $rows + * @param \Illuminate\Support\Collection> $rows * @return array>}> */ private function sectionMap(Collection $rows): array diff --git a/app/Services/ApplicationUrlService.php b/app/Services/ApplicationUrlService.php index a175d085..d30ad0f5 100644 --- a/app/Services/ApplicationUrlService.php +++ b/app/Services/ApplicationUrlService.php @@ -2,7 +2,6 @@ namespace App\Services; -use App\Http\Controllers\Api\Reports\FilesController; use Illuminate\Support\Facades\Route; /** @@ -139,10 +138,10 @@ final class ApplicationUrlService return route('api.timeoff.notify', ['token' => $token]); } - /** Served by {@see FilesController::receipt} (uploads/receipts). */ + /** Served by {@see \App\Http\Controllers\Api\Reports\FilesController::receipt} (uploads/receipts). */ public function forReceiptStorage(?string $filename): ?string { - if (! $filename) { + if (!$filename) { return null; } $safe = basename(trim($filename)); @@ -150,10 +149,10 @@ final class ApplicationUrlService return $safe !== '' ? route('api.v1.files.receipt', ['name' => $safe]) : null; } - /** Served by {@see FilesController::reimb} (uploads/reimbursements). */ + /** Served by {@see \App\Http\Controllers\Api\Reports\FilesController::reimb} (uploads/reimbursements). */ public function forReimbursementStorage(?string $filename): ?string { - if (! $filename) { + if (!$filename) { return null; } $safe = basename(trim($filename)); diff --git a/app/Services/Assignment/AssignmentDataLoaderService.php b/app/Services/Assignment/AssignmentDataLoaderService.php index 7fcbdacb..aea5efed 100644 --- a/app/Services/Assignment/AssignmentDataLoaderService.php +++ b/app/Services/Assignment/AssignmentDataLoaderService.php @@ -31,7 +31,7 @@ class AssignmentDataLoaderService ->get() ->map(function ($row) { $row->teacher_full_name = trim( - ((string) optional($row->teacher)->firstname).' '. + ((string) optional($row->teacher)->firstname) . ' ' . ((string) optional($row->teacher)->lastname) ); diff --git a/app/Services/Assignment/AssignmentSectionService.php b/app/Services/Assignment/AssignmentSectionService.php index 5db2b2db..2c345fe6 100644 --- a/app/Services/Assignment/AssignmentSectionService.php +++ b/app/Services/Assignment/AssignmentSectionService.php @@ -20,7 +20,6 @@ class AssignmentSectionService ->get() ->mapWithKeys(function ($section) { $name = $section->class_section_name ?? $section->section_name ?? $section->name ?? ''; - return [(int) $section->class_section_id => (string) $name]; }) ->all(); diff --git a/app/Services/Assignment/AssignmentService.php b/app/Services/Assignment/AssignmentService.php index 67127e05..f3d59b0d 100644 --- a/app/Services/Assignment/AssignmentService.php +++ b/app/Services/Assignment/AssignmentService.php @@ -93,7 +93,7 @@ class AssignmentService ]); $students = $studentRows - ->filter(fn ($row) => ! empty($row->student)) + ->filter(fn ($row) => !empty($row->student)) ->map(function ($row) { $student = $row->student; @@ -122,10 +122,10 @@ class AssignmentService 'description' => (string) $descriptionMeta, ]; }) - ->filter() - ->sortBy('class_section_name', SORT_NATURAL | SORT_FLAG_CASE) - ->values() - ->all(); + ->filter() + ->sortBy('class_section_name', SORT_NATURAL | SORT_FLAG_CASE) + ->values() + ->all(); return [ 'classSections' => $classSections, @@ -220,7 +220,7 @@ class AssignmentService ]); $students = $studentRows - ->filter(fn ($row) => ! empty($row->student)) + ->filter(fn ($row) => !empty($row->student)) ->map(function ($row) { $student = $row->student; @@ -249,10 +249,10 @@ class AssignmentService 'description' => (string) $descriptionMeta, ]; }) - ->filter() - ->sortBy('class_section_name', SORT_NATURAL | SORT_FLAG_CASE) - ->values() - ->all(); + ->filter() + ->sortBy('class_section_name', SORT_NATURAL | SORT_FLAG_CASE) + ->values() + ->all(); return [ 'classSections' => $classSections, diff --git a/app/Services/AssignmentService.php b/app/Services/AssignmentService.php index 7b18c92b..e1f3985a 100644 --- a/app/Services/AssignmentService.php +++ b/app/Services/AssignmentService.php @@ -4,4 +4,6 @@ namespace App\Services; use App\Services\Assignment\AssignmentService as AssignmentDomainService; -class AssignmentService extends AssignmentDomainService {} +class AssignmentService extends AssignmentDomainService +{ +} diff --git a/app/Services/Attendance/AttendanceAutoPublishJobService.php b/app/Services/Attendance/AttendanceAutoPublishJobService.php index e4d23f11..88e763af 100644 --- a/app/Services/Attendance/AttendanceAutoPublishJobService.php +++ b/app/Services/Attendance/AttendanceAutoPublishJobService.php @@ -3,11 +3,14 @@ namespace App\Services\Attendance; use DateTimeImmutable; +use DateTimeZone; use Illuminate\Support\Facades\DB; class AttendanceAutoPublishJobService { - public function __construct(private AttendanceAutoPublishService $autoPublish) {} + public function __construct(private AttendanceAutoPublishService $autoPublish) + { + } public function run(?DateTimeImmutable $now = null): array { diff --git a/app/Services/Attendance/AttendanceAutoPublishService.php b/app/Services/Attendance/AttendanceAutoPublishService.php index f856bf27..c595e1e8 100644 --- a/app/Services/Attendance/AttendanceAutoPublishService.php +++ b/app/Services/Attendance/AttendanceAutoPublishService.php @@ -2,7 +2,6 @@ namespace App\Services\Attendance; -use Config\School; use DateTimeImmutable; use DateTimeZone; @@ -10,7 +9,7 @@ class AttendanceAutoPublishService { public function timezone(?string $tzFromCfg = null): DateTimeZone { - $tz = $tzFromCfg ?: (class_exists(School::class) + $tz = $tzFromCfg ?: (class_exists(\Config\School::class) ? (config('School')->attendance['timezone'] ?? null) : null); @@ -20,7 +19,7 @@ class AttendanceAutoPublishService public function secondSundayAfterEndOfDay(string $ymd, ?string $tz = null): string { $zone = $this->timezone($tz); - $day = new DateTimeImmutable($ymd.' 00:00:00', $zone); + $day = new DateTimeImmutable($ymd . ' 00:00:00', $zone); $weekday = (int) $day->format('w'); $daysToNextSunday = (7 - $weekday) % 7; diff --git a/app/Services/Attendance/AttendanceCommentService.php b/app/Services/Attendance/AttendanceCommentService.php index ad651af7..87045929 100644 --- a/app/Services/Attendance/AttendanceCommentService.php +++ b/app/Services/Attendance/AttendanceCommentService.php @@ -29,13 +29,13 @@ class AttendanceCommentService $lastChar = $name !== '' ? substr($name, -1) : ''; $namePossessive = ($name === 'This student') ? "This student's" - : ($lastChar === 's' || $lastChar === 'S' ? ($name."'") : ($name."'s")); + : ($lastChar === 's' || $lastChar === 'S' ? ($name . "'") : ($name . "'s")); if (strpos($text, '{name}') !== false) { return str_replace('{name}', $namePossessive, $text); } - return $namePossessive.' '.$text; + return $namePossessive . ' ' . $text; } public function templateForScore(float $score): ?array diff --git a/app/Services/Attendance/AttendanceConsequenceService.php b/app/Services/Attendance/AttendanceConsequenceService.php index e5feb389..6551d529 100644 --- a/app/Services/Attendance/AttendanceConsequenceService.php +++ b/app/Services/Attendance/AttendanceConsequenceService.php @@ -12,7 +12,8 @@ class AttendanceConsequenceService public function __construct( private EmailService $emailService, private UserNotificationDispatchService $notifier - ) {} + ) { + } public function sendFollowUp(array $payload): array { @@ -54,10 +55,10 @@ class AttendanceConsequenceService string $_viewName, string $logLevel ): array { - $studentName = trim((string) ($payload['student']['firstname'] ?? '').' '.(string) ($payload['student']['lastname'] ?? '')); + $studentName = trim((string) ($payload['student']['firstname'] ?? '') . ' ' . (string) ($payload['student']['lastname'] ?? '')); $parentEmail = (string) ($payload['parent']['email'] ?? ''); $parentName = (string) ($payload['parent']['name'] ?? ''); - $teacherName = trim((string) ($payload['teacher']['firstname'] ?? '').' '.(string) ($payload['teacher']['lastname'] ?? '')); + $teacherName = trim((string) ($payload['teacher']['firstname'] ?? '') . ' ' . (string) ($payload['teacher']['lastname'] ?? '')); $className = (string) ($payload['class']['class_section_name'] ?? ''); $semester = (string) ($payload['semester'] ?? ''); $schoolYear = (string) ($payload['school_year'] ?? ''); @@ -68,7 +69,6 @@ class AttendanceConsequenceService Log::warning("Attendance {$type}: missing parent email", [ 'student_id' => $payload['student_id'] ?? null, ]); - return ['ok' => false, 'message' => 'Missing parent email.']; } @@ -76,21 +76,21 @@ class AttendanceConsequenceService $html = trim((string) ($payload['html'] ?? '')); if ($html === '') { - $period = trim($semester.' '.$schoolYear); - $html = '

'.e($subject).'

' - .'

Student: '.e($studentName).'

' - .'

Parent: '.e($parentName).'

' - .'

Teacher: '.e($teacherName).'

' - .'

Class: '.e($className).'

' - .($period !== '' ? '

Term: '.e($period).'

' : '') - .'

Date: '.e($dateFmt).'

'; + $period = trim($semester . ' ' . $schoolYear); + $html = '

' . e($subject) . '

' + . '

Student: ' . e($studentName) . '

' + . '

Parent: ' . e($parentName) . '

' + . '

Teacher: ' . e($teacherName) . '

' + . '

Class: ' . e($className) . '

' + . ($period !== '' ? '

Term: ' . e($period) . '

' : '') + . '

Date: ' . e($dateFmt) . '

'; } $ok = false; try { $ok = $this->emailService->send($parentEmail, $subject, $html, 'attendance'); } catch (\Throwable $e) { - Log::error('Attendance email send failed: '.$e->getMessage()); + Log::error('Attendance email send failed: ' . $e->getMessage()); } $summary = $this->buildInAppSummary($type, $studentName, $dateFmt); @@ -106,11 +106,11 @@ class AttendanceConsequenceService ); } - if (! empty($payload['tracking_id'])) { + if (!empty($payload['tracking_id'])) { AttendanceTracking::markAsNotified((int) $payload['tracking_id']); } - Log::log($logLevel, "Attendance {$type} email ".($ok ? 'sent' : 'failed'), [ + Log::log($logLevel, "Attendance {$type} email " . ($ok ? 'sent' : 'failed'), [ 'student_id' => $payload['student_id'] ?? null, 'recipient' => $parentEmail, ]); @@ -122,8 +122,7 @@ class AttendanceConsequenceService { $name = $studentName !== '' ? " — {$studentName}" : ''; $date = $dateFmt !== '' ? " ({$dateFmt})" : ''; - - return $base.$name.$date; + return $base . $name . $date; } private function buildInAppSummary(string $type, string $studentName, string $dateFmt): string diff --git a/app/Services/Attendance/AttendanceDailySummaryService.php b/app/Services/Attendance/AttendanceDailySummaryService.php index 76879333..0a838a2c 100644 --- a/app/Services/Attendance/AttendanceDailySummaryService.php +++ b/app/Services/Attendance/AttendanceDailySummaryService.php @@ -11,19 +11,18 @@ class AttendanceDailySummaryService public function __construct( private UserNotificationDispatchService $notifier, private EmailService $emailService - ) {} + ) { + } public function sendAbsenteesSummary(): int { $rows = $this->fetchTodaySummary('absent'); - return $this->notifyParents($rows, 'absent'); } public function sendLatesSummary(): int { $rows = $this->fetchTodaySummary('late'); - return $this->notifyParents($rows, 'late'); } @@ -50,12 +49,12 @@ class AttendanceDailySummaryService if ($type === 'absent') { $query->where(function ($w) { - $w->whereIn(DB::raw('UPPER(TRIM(ad.status))'), ['ABSENT', 'ABS', 'A']) + $w->whereIn(DB::raw("UPPER(TRIM(ad.status))"), ['ABSENT', 'ABS', 'A']) ->orWhereRaw("UPPER(TRIM(ad.status)) LIKE 'ABS%'"); }); } else { $query->where(function ($w) { - $w->whereIn(DB::raw('UPPER(TRIM(ad.status))'), ['LATE', 'L']) + $w->whereIn(DB::raw("UPPER(TRIM(ad.status))"), ['LATE', 'L']) ->orWhereRaw("UPPER(TRIM(ad.status)) LIKE 'LATE%'"); }); } @@ -72,7 +71,7 @@ class AttendanceDailySummaryService continue; } - $studentName = trim((string) ($row['student_firstname'] ?? '').' '.(string) ($row['student_lastname'] ?? '')); + $studentName = trim((string) ($row['student_firstname'] ?? '') . ' ' . (string) ($row['student_lastname'] ?? '')); $date = substr((string) ($row['date'] ?? ''), 0, 10); $message = sprintf( @@ -86,7 +85,7 @@ class AttendanceDailySummaryService $email = (string) ($row['parent_email'] ?? ''); if ($email !== '') { - $body = '

'.e($message).'

'; + $body = '

' . e($message) . '

'; $this->emailService->send($email, 'Daily Attendance Update', $body, 'attendance'); } diff --git a/app/Services/Attendance/AttendancePolicyService.php b/app/Services/Attendance/AttendancePolicyService.php index 62ab27ce..af94f50f 100644 --- a/app/Services/Attendance/AttendancePolicyService.php +++ b/app/Services/Attendance/AttendancePolicyService.php @@ -3,14 +3,15 @@ namespace App\Services\Attendance; use App\Models\Role; +use Illuminate\Contracts\Auth\Authenticatable; class AttendancePolicyService { public function canEditDay(array $dayRow, array $currentUser): bool { - $status = strtolower((string) ($dayRow['status'] ?? 'draft')); - $roles = array_map([$this, 'normalizeRole'], (array) ($currentUser['roles'] ?? [])); - $permissions = array_map('strtolower', (array) ($currentUser['permissions'] ?? [])); + $status = strtolower((string)($dayRow['status'] ?? 'draft')); + $roles = array_map([$this, 'normalizeRole'], (array)($currentUser['roles'] ?? [])); + $permissions = array_map('strtolower', (array)($currentUser['permissions'] ?? [])); $isAdmin = $this->isAdminLike($roles, $permissions); $isTeacher = in_array('teacher', $roles, true) || in_array('ta', $roles, true) || in_array('teacher_assistant', $roles, true); @@ -33,7 +34,6 @@ class AttendancePolicyService public function isTeacher(array $roles): bool { $roles = array_map([$this, 'normalizeRole'], $roles); - return in_array('teacher', $roles, true) || in_array('ta', $roles, true) || in_array('teacher_assistant', $roles, true) @@ -45,7 +45,7 @@ class AttendancePolicyService $roles = array_map([$this, 'normalizeRole'], $roles); $adminTokens = $this->adminRoleTokens(); - if (! empty($adminTokens) && count(array_intersect($roles, $adminTokens)) > 0) { + if (!empty($adminTokens) && count(array_intersect($roles, $adminTokens)) > 0) { return true; } @@ -61,7 +61,7 @@ class AttendancePolicyService public function normalizeRole(?string $role): string { - return str_replace([' ', '-'], '_', strtolower(trim((string) $role))); + return str_replace([' ', '-'], '_', strtolower(trim((string)$role))); } public function canManageEarlyDismissals(array $userRoles): bool @@ -123,7 +123,6 @@ class AttendancePolicyService } $cache = array_keys($tokens); - return $cache; } } diff --git a/app/Services/Attendance/AttendanceQueryService.php b/app/Services/Attendance/AttendanceQueryService.php index 7af2d11c..0ce9ebc1 100644 --- a/app/Services/Attendance/AttendanceQueryService.php +++ b/app/Services/Attendance/AttendanceQueryService.php @@ -42,7 +42,7 @@ class AttendanceQueryService $sectionCodes = array_keys($bySection); $labels = []; - if (! empty($sectionCodes)) { + if (!empty($sectionCodes)) { $rows = $this->classSection ->query() ->select(['class_section_id', 'class_section_name']) @@ -52,13 +52,13 @@ class AttendanceQueryService ->toArray(); foreach ($rows as $row) { - $code = (int) $row['class_section_id']; - $name = trim((string) ($row['class_section_name'] ?? '')); - $labels[$code] = $name !== '' ? $name : 'Section #'.$code; + $code = (int)$row['class_section_id']; + $name = trim((string)($row['class_section_name'] ?? '')); + $labels[$code] = $name !== '' ? $name : 'Section #' . $code; } foreach ($sectionCodes as $code) { - $labels[$code] ??= 'Section #'.$code; + $labels[$code] ??= 'Section #' . $code; } } @@ -67,10 +67,10 @@ class AttendanceQueryService if ($sectionCode > 0) { $assigned = $this->teacherClass->assignedForSectionTerm($sectionCode, $semester, $schoolYear); - $teacherIds = array_map(fn ($r) => (int) $r['teacher_id'], $assigned); + $teacherIds = array_map(fn($r) => (int)$r['teacher_id'], $assigned); $statusMap = []; - if (! empty($teacherIds)) { + if (!empty($teacherIds)) { $rows = DB::table('staff_attendance as sa') ->select('sa.user_id', 'sa.status', 'sa.reason') ->where('sa.semester', $semester) @@ -80,7 +80,7 @@ class AttendanceQueryService ->get(); foreach ($rows as $row) { - $statusMap[(int) $row->user_id] = [ + $statusMap[(int)$row->user_id] = [ 'status' => $row->status, 'reason' => $row->reason, ]; @@ -88,15 +88,15 @@ class AttendanceQueryService } foreach ($assigned as $teacher) { - $teacherId = (int) $teacher['teacher_id']; - $position = strtolower((string) ($teacher['position'] ?? 'main')); + $teacherId = (int)$teacher['teacher_id']; + $position = strtolower((string)($teacher['position'] ?? 'main')); $position = in_array($position, ['main', 'ta'], true) ? $position : 'main'; - $name = trim(($teacher['firstname'] ?? '').' '.($teacher['lastname'] ?? '')); + $name = trim(($teacher['firstname'] ?? '') . ' ' . ($teacher['lastname'] ?? '')); $cell = $statusMap[$teacherId] ?? ['status' => null, 'reason' => null]; $grid[] = [ 'teacher_id' => $teacherId, - 'name' => $name !== '' ? $name : 'User#'.$teacherId, + 'name' => $name !== '' ? $name : 'User#' . $teacherId, 'position' => $position, 'status' => $cell['status'], 'reason' => $cell['reason'], @@ -125,13 +125,13 @@ class AttendanceQueryService public function teacherAttendanceFormData(?int $userId, int $requestedSectionId = 0): array { - if (! $userId) { + if (!$userId) { throw new RuntimeException('User not logged in.'); } $teacher = $this->user->find($userId); $teacherName = $teacher - ? trim(($teacher->firstname ?? '').' '.($teacher->lastname ?? '')) + ? trim(($teacher->firstname ?? '') . ' ' . ($teacher->lastname ?? '')) : 'Unknown Teacher'; $semester = $this->attendanceService->currentSemester(); @@ -145,8 +145,8 @@ class AttendanceQueryService $activeSection = null; foreach ($assignments as $assignment) { - $cid = (int) ($assignment['class_section_id'] ?? 0); - $pk = (int) ($assignment['class_section_pk'] ?? 0); + $cid = (int)($assignment['class_section_id'] ?? 0); + $pk = (int)($assignment['class_section_pk'] ?? 0); if ($requestedSectionId > 0 && ($requestedSectionId === $cid || $requestedSectionId === $pk)) { $activeSection = $assignment; @@ -156,8 +156,8 @@ class AttendanceQueryService $activeSection ??= $assignments[0]; - $classSectionCode = (int) ($activeSection['class_section_id'] ?? 0); - $classSectionPk = (int) ($activeSection['class_section_pk'] ?? 0); + $classSectionCode = (int)($activeSection['class_section_id'] ?? 0); + $classSectionPk = (int)($activeSection['class_section_pk'] ?? 0); $classSectionId = $classSectionCode > 0 ? $classSectionCode : $classSectionPk; if ($classSectionId <= 0) { @@ -183,11 +183,11 @@ class AttendanceQueryService $lockedByStudent = []; $attendanceTable = $this->attendanceData->getTable(); - $dateInSundaysSql = 'DATE(`'.$attendanceTable.'`.`date`) IN ('. - implode(',', array_fill(0, count($sundayDates), '?')).')'; + $dateInSundaysSql = 'DATE(`' . $attendanceTable . '`.`date`) IN (' . + implode(',', array_fill(0, count($sundayDates), '?')) . ')'; foreach ($students as $student) { - $studentId = (int) $student['id']; + $studentId = (int)$student['id']; $rows = AttendanceData::query() ->select(['date', 'status', 'is_reported', 'reason', 'modified_by']) @@ -202,7 +202,7 @@ class AttendanceQueryService }) ->whereRaw($dateInSundaysSql, $sundayDates) ->get() - ->map(fn ($row) => (array) $row) + ->map(fn($row) => (array)$row) ->all(); $rows = $this->attendanceService->normalizeAttendanceEntries($rows); @@ -226,8 +226,8 @@ class AttendanceQueryService $recentHistory = []; foreach ($recentRows as $row) { $recentHistory[] = [ - 'date' => substr((string) ($row['date'] ?? ''), 0, 10), - 'status' => strtolower((string) ($row['status'] ?? '')), + 'date' => substr((string)($row['date'] ?? ''), 0, 10), + 'status' => strtolower((string)($row['status'] ?? '')), ]; } @@ -253,7 +253,7 @@ class AttendanceQueryService // missed rows (SQL/driver quirks), still show statuses that match the visible columns. foreach ($recentRows as $row) { $d = $this->calendarDateKey($row['date'] ?? null); - if ($d === '' || ! in_array($d, $sundayDates, true)) { + if ($d === '' || !in_array($d, $sundayDates, true)) { continue; } $rowStatus = $row['status'] ?? null; @@ -340,13 +340,13 @@ class AttendanceQueryService $teacherRows = []; - if (! empty($assigned)) { - $teacherIds = array_map(static fn ($r) => (int) $r['teacher_id'], $assigned); + if (!empty($assigned)) { + $teacherIds = array_map(static fn($r) => (int)$r['teacher_id'], $assigned); $statusMap = []; - if (! empty($teacherIds)) { - $staffDateInSql = 'DATE(`sa`.`date`) IN ('. - implode(',', array_fill(0, count($sundayDates), '?')).')'; + if (!empty($teacherIds)) { + $staffDateInSql = 'DATE(`sa`.`date`) IN (' . + implode(',', array_fill(0, count($sundayDates), '?')) . ')'; $staffQ = DB::table('staff_attendance as sa') ->select('sa.user_id', 'sa.date', 'sa.status', 'sa.reason') ->where('sa.semester', $semester) @@ -372,7 +372,7 @@ class AttendanceQueryService if ($dk === '') { continue; } - $statusMap[(int) $row->user_id][$dk] = [ + $statusMap[(int)$row->user_id][$dk] = [ 'status' => $row->status, 'reason' => $row->reason, ]; @@ -380,10 +380,10 @@ class AttendanceQueryService } foreach ($assigned as $teacher) { - $teacherId = (int) $teacher['teacher_id']; - $position = strtolower((string) ($teacher['position'] ?? 'main')); + $teacherId = (int)$teacher['teacher_id']; + $position = strtolower((string)($teacher['position'] ?? 'main')); $position = in_array($position, ['main', 'ta'], true) ? $position : 'main'; - $name = trim(($teacher['firstname'] ?? '').' '.($teacher['lastname'] ?? '')); + $name = trim(($teacher['firstname'] ?? '') . ' ' . ($teacher['lastname'] ?? '')); $history = []; foreach ($sundayDates as $date) { @@ -400,7 +400,7 @@ class AttendanceQueryService $teacherRows[] = [ 'teacher_id' => $teacherId, 'position' => $position, - 'name' => $name !== '' ? $name : 'User#'.$teacherId, + 'name' => $name !== '' ? $name : 'User#' . $teacherId, 'sunday_statuses' => $history, 'today' => $history[$currentSunday] ?? null, 'today_reason' => $todayReason, @@ -410,8 +410,8 @@ class AttendanceQueryService $noSchoolDays = []; $calendarTable = $this->calendar->getTable(); - $calDateInSql = 'DATE(`'.$calendarTable.'`.`date`) IN ('. - implode(',', array_fill(0, count($sundayDates), '?')).')'; + $calDateInSql = 'DATE(`' . $calendarTable . '`.`date`) IN (' . + implode(',', array_fill(0, count($sundayDates), '?')) . ')'; $calendarRows = $this->calendar->query() ->where('no_school', 1) ->whereRaw($calDateInSql, $sundayDates) @@ -438,9 +438,9 @@ class AttendanceQueryService 'class_section_id' => $classSectionId, 'sunday_dates' => $sundayDates, 'current_sunday' => $currentSunday, - 'enable_attendance' => (int) $this->configuration->getConfig('enable_attendance'), - 'can_edit' => ((int) $this->configuration->getConfig('enable_attendance') === 1), - 'class_id' => (int) $this->classSection->getClassId($classSectionId), + 'enable_attendance' => (int)$this->configuration->getConfig('enable_attendance'), + 'can_edit' => ((int)$this->configuration->getConfig('enable_attendance') === 1), + 'class_id' => (int)$this->classSection->getClassId($classSectionId), 'no_school_days' => $noSchoolDays, 'today' => $currentSunday, 'locked_by_student' => $lockedByStudent, @@ -463,7 +463,7 @@ class AttendanceQueryService ->where('sc.school_year', $schoolYear) ->groupBy('classSection.id', 'classSection.class_id', 'classSection.class_section_id', 'classSection.class_section_name') ->get() - ->map(fn ($row) => $row->toArray()) + ->map(fn($row) => $row->toArray()) ->all(); }; @@ -492,32 +492,32 @@ class AttendanceQueryService $sectionCounts = $this->studentClass->getStudentCountsBySection($effectiveTermYear); foreach ($classSections as $classSection) { - $secPk = (int) ($classSection['id'] ?? 0); - $secCodeRaw = (string) ($classSection['class_section_id'] ?? ''); - $secCode = $secCodeRaw !== '' ? $secCodeRaw : (string) $secPk; - $classId = (int) ($classSection['class_id'] ?? 0); + $secPk = (int)($classSection['id'] ?? 0); + $secCodeRaw = (string)($classSection['class_section_id'] ?? ''); + $secCode = $secCodeRaw !== '' ? $secCodeRaw : (string)$secPk; + $classId = (int)($classSection['class_id'] ?? 0); $studentsBySection[$secCode] = []; $datesBySection[$secCode] = []; $attendanceData[$secCode] = []; $attendanceRecord[$secCode] = []; - $countForCode = (int) ($sectionCounts[$secCode] ?? 0); - $countForPk = (int) ($sectionCounts[$secPk] ?? 0); + $countForCode = (int)($sectionCounts[$secCode] ?? 0); + $countForPk = (int)($sectionCounts[$secPk] ?? 0); $sectionHasStudents = ($countForCode + $countForPk) > 0; $students = $this->studentClass->getClassStudents($secCode, $effectiveTermYear); - if (! $students && $secPk && (string) $secPk !== (string) $secCode) { + if (!$students && $secPk && (string)$secPk !== (string)$secCode) { $students = $this->studentClass->getClassStudents($secPk, $effectiveTermYear); } - if (! $sectionHasStudents || ! $students) { + if (!$sectionHasStudents || !$students) { continue; } // Bulk-load student profiles for the whole section in one query $studentsArray = is_array($students) ? $students : $students->toArray(); - $studentIds = array_map(fn ($sc) => (int) ($sc['student_id'] ?? $sc->student_id ?? 0), $studentsArray); + $studentIds = array_map(fn($sc) => (int)($sc['student_id'] ?? $sc->student_id ?? 0), $studentsArray); $studentProfiles = $this->student ->query() ->select(['id', 'firstname', 'lastname', 'school_id']) @@ -525,13 +525,12 @@ class AttendanceQueryService ->where('is_active', 1) ->get() ->keyBy('id') - ->map(fn ($row) => $row->toArray()) + ->map(fn($row) => $row->toArray()) ->all(); $activeIds = array_keys($studentProfiles); if (empty($activeIds)) { unset($studentsBySection[$secCode], $datesBySection[$secCode], $attendanceData[$secCode], $attendanceRecord[$secCode]); - continue; } @@ -540,17 +539,17 @@ class AttendanceQueryService ->whereIn('student_id', $activeIds) ->where(function ($q) use ($secCode, $secPk) { $q->where('class_section_id', $secCode); - if ($secPk && (string) $secPk !== (string) $secCode) { + if ($secPk && (string)$secPk !== (string)$secCode) { $q->orWhere('class_section_id', $secPk); } }) - ->when($termSemester !== '', fn ($q) => $q->where('semester', $termSemester)) - ->when($effectiveTermYear !== '', fn ($q) => $q->where('school_year', $effectiveTermYear)) + ->when($termSemester !== '', fn($q) => $q->where('semester', $termSemester)) + ->when($effectiveTermYear !== '', fn($q) => $q->where('school_year', $effectiveTermYear)) ->orderBy('date') ->get() - ->map(fn ($row) => $row->toArray()) + ->map(fn($row) => $row->toArray()) ->groupBy('student_id') - ->map(fn ($group) => $group->values()->all()) + ->map(fn($group) => $group->values()->all()) ->all(); // Bulk-load all attendance records (summaries) for the section in one query @@ -558,36 +557,36 @@ class AttendanceQueryService ->whereIn('student_id', $activeIds) ->where(function ($q) use ($secCode, $secPk) { $q->where('class_section_id', $secCode); - if ($secPk && (string) $secPk !== (string) $secCode) { + if ($secPk && (string)$secPk !== (string)$secCode) { $q->orWhere('class_section_id', $secPk); } }) - ->when($termSemester !== '', fn ($q) => $q->where('semester', $termSemester)) - ->when($effectiveTermYear !== '', fn ($q) => $q->where('school_year', $effectiveTermYear)) + ->when($termSemester !== '', fn($q) => $q->where('semester', $termSemester)) + ->when($effectiveTermYear !== '', fn($q) => $q->where('school_year', $effectiveTermYear)) ->get() ->keyBy('student_id') - ->map(fn ($row) => $row->toArray()) + ->map(fn($row) => $row->toArray()) ->all(); $hasRoster = false; foreach ($studentIds as $studentId) { $student = $studentProfiles[$studentId] ?? null; - if (! $student) { + if (!$student) { continue; } $studentsBySection[$secCode][] = $student; - $studentSchoolMap[$studentId] = (string) ($student['school_id'] ?? ''); + $studentSchoolMap[$studentId] = (string)($student['school_id'] ?? ''); $hasRoster = true; $entries = $this->attendanceService->normalizeAttendanceEntries( - array_map(fn ($r) => (array) $r, $allEntries[$studentId] ?? []) + array_map(fn($r) => (array)$r, $allEntries[$studentId] ?? []) ); $attendanceData[$secCode][$studentId] = $entries; foreach ($entries as $entry) { - $d = (string) ($entry['date'] ?? ''); + $d = (string)($entry['date'] ?? ''); if ($d !== '') { $datesBySection[$secCode][$d] = true; } @@ -601,9 +600,8 @@ class AttendanceQueryService ]; } - if (! $hasRoster) { + if (!$hasRoster) { unset($studentsBySection[$secCode], $datesBySection[$secCode], $attendanceData[$secCode], $attendanceRecord[$secCode]); - continue; } @@ -612,7 +610,7 @@ class AttendanceQueryService foreach ($attendanceData as $secId => &$studentEntries) { foreach ($studentEntries as &$entries) { - usort($entries, static fn ($a, $b) => strcmp((string) ($a['date'] ?? ''), (string) ($b['date'] ?? ''))); + usort($entries, static fn($a, $b) => strcmp((string)($a['date'] ?? ''), (string)($b['date'] ?? ''))); } } unset($studentEntries, $entries); @@ -646,9 +644,9 @@ class AttendanceQueryService ->toArray(); foreach ($events as $event) { - $d = substr((string) ($event['date'] ?? ''), 0, 10); + $d = substr((string)($event['date'] ?? ''), 0, 10); if ($d !== '') { - $noSchoolDays[$d] = trim((string) ($event['title'] ?? 'No School')) ?: 'No School'; + $noSchoolDays[$d] = trim((string)($event['title'] ?? 'No School')) ?: 'No School'; } } @@ -670,12 +668,12 @@ class AttendanceQueryService foreach ($studentEntries as $studentId => $entries) { $statusByDate = []; foreach ($entries as $entry) { - $d = substr((string) ($entry['date'] ?? ''), 0, 10); + $d = substr((string)($entry['date'] ?? ''), 0, 10); if ($d === '' || empty($passedDatesSet[$d])) { continue; } - $st = strtolower(trim((string) ($entry['status'] ?? ''))); - if (! in_array($st, ['present', 'absent', 'late'], true)) { + $st = strtolower(trim((string)($entry['status'] ?? ''))); + if (!in_array($st, ['present', 'absent', 'late'], true)) { continue; } $statusByDate[$d] = $st; @@ -697,9 +695,9 @@ class AttendanceQueryService $sum = $p + $l + $a; $record = $attendanceRecord[$secCode][$studentId] ?? []; - $storedSum = (int) ($record['total_presence'] ?? 0) - + (int) ($record['total_late'] ?? 0) - + (int) ($record['total_absence'] ?? 0); + $storedSum = (int)($record['total_presence'] ?? 0) + + (int)($record['total_late'] ?? 0) + + (int)($record['total_absence'] ?? 0); if ($storedSum !== $totalPassedDays && $storedSum !== $sum) { DB::table('attendance_record') @@ -735,7 +733,7 @@ class AttendanceQueryService if (auth()->id()) { $u = $this->user->query()->select('firstname', 'lastname')->find(auth()->id()); if ($u) { - $adminName = trim(($u->firstname ?? '').' '.($u->lastname ?? '')); + $adminName = trim(($u->firstname ?? '') . ' ' . ($u->lastname ?? '')); } } @@ -775,8 +773,8 @@ class AttendanceQueryService return []; } - $staffDateInSql = 'DATE(`sa`.`date`) IN ('. - implode(',', array_fill(0, count($sundayDates), '?')).')'; + $staffDateInSql = 'DATE(`sa`.`date`) IN (' . + implode(',', array_fill(0, count($sundayDates), '?')) . ')'; $run = static function ( bool $requireTcSemester, @@ -832,8 +830,8 @@ class AttendanceQueryService return []; } - $staffDateInSql = 'DATE(`sa`.`date`) IN ('. - implode(',', array_fill(0, count($sundayDates), '?')).')'; + $staffDateInSql = 'DATE(`sa`.`date`) IN (' . + implode(',', array_fill(0, count($sundayDates), '?')) . ')'; $ids = []; @@ -907,7 +905,7 @@ class AttendanceQueryService */ private function calendarDateKey(mixed $value): string { - $s = trim((string) ($value ?? '')); + $s = trim((string)($value ?? '')); if ($s === '') { return ''; } diff --git a/app/Services/Attendance/AttendanceRecordSyncService.php b/app/Services/Attendance/AttendanceRecordSyncService.php index 8933c88e..47771b95 100644 --- a/app/Services/Attendance/AttendanceRecordSyncService.php +++ b/app/Services/Attendance/AttendanceRecordSyncService.php @@ -25,16 +25,16 @@ class AttendanceRecordSyncService ->where('school_year', $schoolYear) ->first(); - if (! $record) { + if (!$record) { return; } $newStatus = strtolower($newStatus); - $oldStatus = strtolower((string) $oldStatus); + $oldStatus = strtolower((string)$oldStatus); - $presence = (int) ($record->total_presence ?? 0); - $absence = (int) ($record->total_absence ?? 0); - $late = (int) ($record->total_late ?? 0); + $presence = (int)($record->total_presence ?? 0); + $absence = (int)($record->total_absence ?? 0); + $late = (int)($record->total_late ?? 0); if ($oldStatus === 'present') { $presence--; @@ -80,14 +80,13 @@ class AttendanceRecordSyncService if ($record) { $record->update([ - 'total_presence' => (int) ($record->total_presence ?? 0) + ($status === 'present' ? 1 : 0), - 'total_absence' => (int) ($record->total_absence ?? 0) + ($status === 'absent' ? 1 : 0), - 'total_late' => (int) ($record->total_late ?? 0) + ($status === 'late' ? 1 : 0), - 'total_attendance' => (int) ($record->total_attendance ?? 0) + 1, + 'total_presence' => (int)($record->total_presence ?? 0) + ($status === 'present' ? 1 : 0), + 'total_absence' => (int)($record->total_absence ?? 0) + ($status === 'absent' ? 1 : 0), + 'total_late' => (int)($record->total_late ?? 0) + ($status === 'late' ? 1 : 0), + 'total_attendance' => (int)($record->total_attendance ?? 0) + 1, 'updated_at' => now(), 'modified_by' => $modifiedBy, ]); - return; } @@ -142,13 +141,13 @@ class AttendanceRecordSyncService return $record->update($payload); } - $payload['class_section_id'] = (int) $classSectionId; + $payload['class_section_id'] = (int)$classSectionId; $payload['student_id'] = $studentId; $payload['school_id'] = $schoolId; $payload['semester'] = $semester; $payload['school_year'] = $schoolYear; $payload['created_at'] = now(); - return (bool) AttendanceRecord::query()->create($payload); + return (bool)AttendanceRecord::query()->create($payload); } -} +} \ No newline at end of file diff --git a/app/Services/Attendance/AttendanceService.php b/app/Services/Attendance/AttendanceService.php index 5dc287a7..13985bc1 100644 --- a/app/Services/Attendance/AttendanceService.php +++ b/app/Services/Attendance/AttendanceService.php @@ -27,24 +27,24 @@ class AttendanceService public function currentSemester(): string { - return (string) ($this->configuration->getConfig('semester') ?? 'Fall'); + return (string)($this->configuration->getConfig('semester') ?? 'Fall'); } public function currentSchoolYear(): string { - return (string) ($this->configuration->getConfig('school_year') ?? now()->year.'-'.(now()->year + 1)); + return (string)($this->configuration->getConfig('school_year') ?? now()->year . '-' . (now()->year + 1)); } public function updateAttendanceManagement(Authenticatable $user, array $data): array { - $classSectionId = (int) $data['class_section_id']; - $studentId = (int) $data['student_id']; - $status = strtolower((string) $data['status']); - $date = (string) $data['date']; + $classSectionId = (int)$data['class_section_id']; + $studentId = (int)$data['student_id']; + $status = strtolower((string)$data['status']); + $date = (string)$data['date']; $reason = $data['reason'] ?? null; $classId = $data['class_id'] ?? null; - $semester = (string) ($data['semester'] ?? $this->currentSemester()); - $schoolYear = (string) ($data['school_year'] ?? $this->currentSchoolYear()); + $semester = (string)($data['semester'] ?? $this->currentSemester()); + $schoolYear = (string)($data['school_year'] ?? $this->currentSchoolYear()); $dayRow = AttendanceDay::query() ->where('class_section_id', $classSectionId) @@ -67,11 +67,11 @@ class AttendanceService 'permissions' => method_exists($user, 'permissions') ? $user->permissions->pluck('name')->all() : [], ]; - if (! $this->attendancePolicyService->canEditDay($dayPolicyRow, $currentUser)) { + if (!$this->attendancePolicyService->canEditDay($dayPolicyRow, $currentUser)) { throw new RuntimeException('Attendance is locked for your role.'); } - $reportedRaw = strtolower((string) ($data['is_reported'] ?? '')); + $reportedRaw = strtolower((string)($data['is_reported'] ?? '')); $isReported = $status === 'present' ? 'no' : (in_array($reportedRaw, ['1', 'yes', 'y', 'true', 'on'], true) ? 'yes' : 'no'); @@ -98,7 +98,7 @@ class AttendanceService 'semester' => $semester, 'school_year' => $schoolYear, 'date' => $date, - 'class_id' => (int) $classId, + 'class_id' => (int)$classId, 'user_id' => $user->id, ]); @@ -136,13 +136,13 @@ class AttendanceService public function adminAddEntry(Authenticatable $user, array $data): array { - $classSectionId = (int) $data['class_section_id']; - $studentId = (int) $data['student_id']; - $status = strtolower((string) $data['status']); - $date = (string) ($data['date'] ?? now()->toDateString()); + $classSectionId = (int)$data['class_section_id']; + $studentId = (int)$data['student_id']; + $status = strtolower((string)$data['status']); + $date = (string)($data['date'] ?? now()->toDateString()); $reason = $data['reason'] ?? null; - $isReported = in_array(strtolower((string) ($data['is_reported'] ?? 'no')), ['yes', 'no'], true) - ? strtolower((string) ($data['is_reported'] ?? 'no')) + $isReported = in_array(strtolower((string)($data['is_reported'] ?? 'no')), ['yes', 'no'], true) + ? strtolower((string)($data['is_reported'] ?? 'no')) : 'no'; $section = $this->classSection @@ -152,7 +152,7 @@ class AttendanceService ->orWhere('class_section_id', $classSectionId) ->first(); - $resolvedClassId = (int) ($section->class_id ?? 0); + $resolvedClassId = (int)($section->class_id ?? 0); if ($resolvedClassId <= 0) { throw new RuntimeException('Cannot resolve class_id for this section.'); @@ -210,32 +210,29 @@ class AttendanceService $reportedRaw = $row['is_reported'] ?? ($row['reported'] ?? ''); $row['is_reported'] = $this->normalizeReportedFlag($reportedRaw); } - return $entries; } public function normalizeStatus(?string $status): string { - $status = strtolower(trim((string) $status)); - + $status = strtolower(trim((string)$status)); return in_array($status, ['present', 'absent', 'late'], true) ? $status : $status; } public function normalizeReportedFlag(mixed $flag): string { - $v = strtolower(trim((string) $flag)); - + $v = strtolower(trim((string)$flag)); return in_array($v, ['yes', '1', 'true', 'y', 'on'], true) ? 'yes' : 'no'; } public function detectExternalSubmission(?array $row): array { - if (empty($row) || ! is_array($row)) { + if (empty($row) || !is_array($row)) { return ['locked' => false, 'source' => null]; } - $reportedRaw = strtolower((string) ($row['is_reported'] ?? '')); - $reason = strtolower((string) ($row['reason'] ?? '')); + $reportedRaw = strtolower((string)($row['is_reported'] ?? '')); + $reason = strtolower((string)($row['reason'] ?? '')); $isParent = in_array($reportedRaw, ['yes', '1', 'true', 'y'], true) || str_contains($reason, 'parent-reported') @@ -245,7 +242,7 @@ class AttendanceService return ['locked' => true, 'source' => 'parent']; } - $modifierId = (int) ($row['modified_by'] ?? 0); + $modifierId = (int)($row['modified_by'] ?? 0); if ($modifierId > 0 && $this->isAdminLikeUserId($modifierId)) { return ['locked' => true, 'source' => 'admin']; } @@ -267,12 +264,12 @@ class AttendanceService $excluded = ['parent', 'guest', 'teacher', 'teacher_assistant', 'assistant_teacher', 'ta']; foreach ($roles as $role) { - $name = strtolower(str_replace([' ', '-'], '_', (string) ($role['role_name'] ?? ''))); - if ($name !== '' && ! in_array($name, $excluded, true)) { + $name = strtolower(str_replace([' ', '-'], '_', (string)($role['role_name'] ?? ''))); + if ($name !== '' && !in_array($name, $excluded, true)) { return true; } } return false; } -} +} \ No newline at end of file diff --git a/app/Services/Attendance/AttendanceSummaryRebuildService.php b/app/Services/Attendance/AttendanceSummaryRebuildService.php index 5137e21a..5752aec9 100644 --- a/app/Services/Attendance/AttendanceSummaryRebuildService.php +++ b/app/Services/Attendance/AttendanceSummaryRebuildService.php @@ -29,8 +29,8 @@ class AttendanceSummaryRebuildService $semester = (string) ($row['semester'] ?? ''); $status = strtolower((string) ($row['status'] ?? '')); - $key = $studentId.'-'.$schoolYear.'-'.$semester; - if (! isset($summary[$key])) { + $key = $studentId . '-' . $schoolYear . '-' . $semester; + if (!isset($summary[$key])) { $summary[$key] = [ 'student_id' => $studentId, 'school_year' => $schoolYear, diff --git a/app/Services/Attendance/LateSlipLogQueryService.php b/app/Services/Attendance/LateSlipLogQueryService.php index f603438b..5d27271c 100644 --- a/app/Services/Attendance/LateSlipLogQueryService.php +++ b/app/Services/Attendance/LateSlipLogQueryService.php @@ -11,16 +11,16 @@ class LateSlipLogQueryService { $query = LateSlipLog::query(); - if (! empty($filters['school_year'])) { + if (!empty($filters['school_year'])) { $query->where('school_year', (string) $filters['school_year']); } - if (! empty($filters['semester'])) { + if (!empty($filters['semester'])) { $query->where('semester', (string) $filters['semester']); } - if (! empty($filters['q'])) { - $query->where('student_name', 'like', '%'.$filters['q'].'%'); + if (!empty($filters['q'])) { + $query->where('student_name', 'like', '%' . $filters['q'] . '%'); } $dateFrom = $this->toDbDate($filters['date_from'] ?? null); @@ -58,7 +58,6 @@ class LateSlipLogQueryService return null; } $ts = strtotime($value); - return $ts ? date('Y-m-d', $ts) : null; } } diff --git a/app/Services/Attendance/SemesterRangeService.php b/app/Services/Attendance/SemesterRangeService.php index 4c0870f3..79d80a27 100644 --- a/app/Services/Attendance/SemesterRangeService.php +++ b/app/Services/Attendance/SemesterRangeService.php @@ -9,7 +9,7 @@ class SemesterRangeService { public function normalizeSemester(?string $semester): string { - $value = strtolower(trim((string) $semester)); + $value = strtolower(trim((string)$semester)); return match ($value) { 'fall', 'autumn' => 'Fall', @@ -76,7 +76,7 @@ class SemesterRangeService protected function parseSchoolYear(string $schoolYear): array { if (preg_match('/^\s*(\d{4})\s*-\s*(\d{4})\s*$/', $schoolYear, $m)) { - return [(int) $m[1], (int) $m[2]]; + return [(int)$m[1], (int)$m[2]]; } $configured = trim((string) Configuration::getConfig('school_year')); @@ -85,7 +85,7 @@ class SemesterRangeService } $year = (int) date('Y'); - $derived = $year.'-'.($year + 1); + $derived = $year . '-' . ($year + 1); Configuration::setConfigValueByKey('school_year', $derived); return [$year, $year + 1]; diff --git a/app/Services/Attendance/StaffAttendanceService.php b/app/Services/Attendance/StaffAttendanceService.php index 170c8844..ea380676 100644 --- a/app/Services/Attendance/StaffAttendanceService.php +++ b/app/Services/Attendance/StaffAttendanceService.php @@ -2,14 +2,13 @@ namespace App\Services\Attendance; -use App\Controllers\View\AttendanceController; use App\Models\AttendanceDay; -use App\Models\ClassSection; use App\Models\Configuration; use App\Models\StaffAttendance; use App\Models\TeacherClass; use Carbon\Carbon; use Illuminate\Contracts\Auth\Authenticatable; +use App\Models\ClassSection; use Illuminate\Support\Facades\DB; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -24,7 +23,7 @@ class StaffAttendanceService ) {} /** - * legacy {@see AttendanceController::index} — single date / section teacher grid JSON. + * legacy {@see \App\Controllers\View\AttendanceController::index} — single date / section teacher grid JSON. */ public function teacherAttendanceDayIndex(?string $semester, ?string $schoolYear, string $dateYmd, int $sectionCode): array { @@ -45,7 +44,7 @@ class StaffAttendanceService ->where('class_section_id', $code) ->value('class_section_name'); $name = trim((string) $name); - $labels[$code] = $name !== '' ? $name : ('Section #'.$code); + $labels[$code] = $name !== '' ? $name : ('Section #' . $code); } $grid = []; @@ -77,7 +76,7 @@ class StaffAttendanceService $tid = (int) ($t['teacher_id'] ?? 0); $posRaw = strtolower((string) ($t['position'] ?? 'main')); $pos = in_array($posRaw, ['main', 'ta'], true) ? $posRaw : 'main'; - $name = trim(($t['firstname'] ?? '').' '.($t['lastname'] ?? '')) ?: ('User#'.$tid); + $name = trim(($t['firstname'] ?? '') . ' ' . ($t['lastname'] ?? '')) ?: ('User#' . $tid); $cell = $statusMap[$tid] ?? ['status' => null, 'reason' => null]; @@ -109,7 +108,7 @@ class StaffAttendanceService } /** - * Bulk save for legacy {@see AttendanceController::save} (method missing in legacy; implemented here). + * Bulk save for legacy {@see \App\Controllers\View\AttendanceController::save} (method missing in legacy; implemented here). */ public function saveTeacherAttendanceBulk(Authenticatable $user, array $payload): array { @@ -182,7 +181,7 @@ class StaffAttendanceService public function monthData(?string $semester, ?string $schoolYear): array { - $semester = $semester ?: (string) $this->configuration->getConfig('semester'); + $semester = $semester ?: (string)$this->configuration->getConfig('semester'); [ 'school_year' => $schoolYear, 'current_year' => $currentYear, @@ -233,7 +232,7 @@ class StaffAttendanceService $sectionCodes = array_keys($assignedBySection); $labels = []; - if (! empty($sectionCodes)) { + if (!empty($sectionCodes)) { $rows = $this->classSection->query() ->select(['class_section_id', 'class_section_name']) ->whereIn('class_section_id', $sectionCodes) @@ -241,20 +240,20 @@ class StaffAttendanceService ->toArray(); foreach ($rows as $row) { - $labels[(int) $row['class_section_id']] = trim((string) $row['class_section_name']) ?: 'Section #'.(int) $row['class_section_id']; + $labels[(int)$row['class_section_id']] = trim((string)$row['class_section_name']) ?: 'Section #' . (int)$row['class_section_id']; } } $teacherIds = []; foreach ($assignedBySection as $rows) { foreach ($rows as $row) { - $teacherIds[(int) $row['teacher_id']] = true; + $teacherIds[(int)$row['teacher_id']] = true; } } $teacherIds = array_keys($teacherIds); $statusByTeacher = []; - if (! empty($teacherIds) && ! empty($days)) { + if (!empty($teacherIds) && !empty($days)) { $query = DB::table('staff_attendance') ->select('user_id', 'date', 'status', 'reason') ->where('school_year', $schoolYear) @@ -268,8 +267,8 @@ class StaffAttendanceService $rows = $query->get(); foreach ($rows as $row) { - $statusByTeacher[(int) $row->user_id][(string) $row->date] = [ - 'status' => strtolower((string) $row->status), + $statusByTeacher[(int)$row->user_id][(string)$row->date] = [ + 'status' => strtolower((string)$row->status), 'reason' => $row->reason, ]; } @@ -285,7 +284,7 @@ class StaffAttendanceService $noSchoolDays = []; foreach ($noSchoolRows as $row) { - $noSchoolDays[] = (string) $row->date; + $noSchoolDays[] = (string)$row->date; } $sections = []; @@ -293,9 +292,9 @@ class StaffAttendanceService $teachersPayload = []; foreach (($assignedBySection[$code] ?? []) as $row) { - $teacherId = (int) $row['teacher_id']; - $name = trim(($row['firstname'] ?? '').' '.($row['lastname'] ?? '')) ?: ('User#'.$teacherId); - $position = strtolower((string) ($row['position'] ?? 'main')); + $teacherId = (int)$row['teacher_id']; + $name = trim(($row['firstname'] ?? '') . ' ' . ($row['lastname'] ?? '')) ?: ('User#' . $teacherId); + $position = strtolower((string)($row['position'] ?? 'main')); $position = in_array($position, ['main', 'ta'], true) ? $position : 'main'; $cells = []; @@ -303,7 +302,7 @@ class StaffAttendanceService foreach ($days as $date) { $cell = $statusByTeacher[$teacherId][$date] ?? null; - if (! $cell || empty($cell['status'])) { + if (!$cell || empty($cell['status'])) { continue; } @@ -328,15 +327,15 @@ class StaffAttendanceService } $sections[] = [ - 'section_code' => (int) $code, - 'label' => $labels[$code] ?? ('Section #'.(int) $code), + 'section_code' => (int)$code, + 'label' => $labels[$code] ?? ('Section #' . (int)$code), 'teachers' => $teachersPayload, ]; } $adminStatusByUser = []; $adminIds = []; - if (! empty($days)) { + if (!empty($days)) { $query = DB::table('staff_attendance') ->select('user_id', 'date', 'status', 'reason') ->where('school_year', $schoolYear) @@ -362,7 +361,7 @@ class StaffAttendanceService $adminIds = array_keys($adminIds); $admins = []; - if (! empty($adminIds)) { + if (!empty($adminIds)) { $rolesRows = DB::table('user_roles as ur') ->select('ur.user_id', 'r.name as role_name', 'r.slug as role_slug', 'r.priority') ->join('roles as r', 'r.id', '=', 'ur.role_id') @@ -390,20 +389,20 @@ class StaffAttendanceService $namesByUser = []; foreach ($userRows as $row) { - $namesByUser[(int) $row->id] = trim(((string) ($row->firstname ?? '')).' '.((string) ($row->lastname ?? ''))); + $namesByUser[(int) $row->id] = trim(((string) ($row->firstname ?? '')) . ' ' . ((string) ($row->lastname ?? ''))); } foreach ($adminIds as $uid) { $picked = null; foreach (($rolesByUser[$uid] ?? []) as $role) { $slug = strtolower((string) ($role['role_slug'] ?? $role['role_name'] ?? '')); - if (! in_array($slug, $excludeSlugs, true)) { + if (!in_array($slug, $excludeSlugs, true)) { $picked = $role; break; } } - if (! $picked) { + if (!$picked) { continue; } @@ -411,7 +410,7 @@ class StaffAttendanceService $cells = []; foreach ($days as $date) { $cell = $adminStatusByUser[$uid][$date] ?? null; - if (! $cell || empty($cell['status'])) { + if (!$cell || empty($cell['status'])) { continue; } $cells[$date] = $cell; @@ -426,7 +425,7 @@ class StaffAttendanceService $admins[] = [ 'user_id' => $uid, - 'name' => $namesByUser[$uid] !== '' ? $namesByUser[$uid] : ('User#'.$uid), + 'name' => $namesByUser[$uid] !== '' ? $namesByUser[$uid] : ('User#' . $uid), 'role' => (string) ($picked['role_name'] ?? 'Admin'), 'cells' => $cells, 'totals' => $totals, @@ -509,7 +508,7 @@ class StaffAttendanceService } } - if ($currentYear !== '' && ! in_array($currentYear, $schoolYears, true)) { + if ($currentYear !== '' && !in_array($currentYear, $schoolYears, true)) { array_unshift($schoolYears, $currentYear); } @@ -524,7 +523,7 @@ class StaffAttendanceService ? $requestedSchoolYear : ($currentYear !== '' ? $currentYear : ($schoolYears[0] ?? '')); - if ($resolvedYear !== '' && ! in_array($resolvedYear, $schoolYears, true)) { + if ($resolvedYear !== '' && !in_array($resolvedYear, $schoolYears, true)) { array_unshift($schoolYears, $resolvedYear); } @@ -540,7 +539,7 @@ class StaffAttendanceService protected function buildRangeLabel(string $schoolYear, string $semesterNorm, string $rangeStart, string $rangeEnd): string { if ($semesterNorm === '') { - return 'School Year '.$schoolYear; + return 'School Year ' . $schoolYear; } return sprintf( @@ -554,14 +553,14 @@ class StaffAttendanceService public function adminsAttendanceData(?string $date, ?string $semester, ?string $schoolYear): array { $date = $date ?: now()->toDateString(); - $semester = $semester ?: (string) $this->configuration->getConfig('semester'); - $schoolYear = $schoolYear ?: (string) $this->configuration->getConfig('school_year'); + $semester = $semester ?: (string)$this->configuration->getConfig('semester'); + $schoolYear = $schoolYear ?: (string)$this->configuration->getConfig('school_year'); $allStaff = $this->staffAttendance->staffWithStatusForDay($date, $semester, $schoolYear, []); $userIds = []; foreach ($allStaff as $row) { - $uid = (int) ($row['user_id'] ?? 0); + $uid = (int)($row['user_id'] ?? 0); if ($uid > 0) { $userIds[$uid] = true; } @@ -578,19 +577,19 @@ class StaffAttendanceService $rolesByUser = []; foreach ($rolesRows as $row) { - $rolesByUser[(int) $row->user_id][] = (array) $row; + $rolesByUser[(int)$row->user_id][] = (array)$row; } foreach ($rolesByUser as &$list) { - usort($list, fn ($a, $b) => ((int) ($a['priority'] ?? 100)) <=> ((int) ($b['priority'] ?? 100))); + usort($list, fn($a, $b) => ((int)($a['priority'] ?? 100)) <=> ((int)($b['priority'] ?? 100))); } $excludeSlugs = ['parent', 'guest', 'teacher', 'teacher_assistant', 'ta', 'assistant_teacher']; $staffByUser = []; foreach ($allStaff as $row) { - $uid = (int) ($row['user_id'] ?? 0); - if ($uid > 0 && ! isset($staffByUser[$uid])) { + $uid = (int)($row['user_id'] ?? 0); + if ($uid > 0 && !isset($staffByUser[$uid])) { $staffByUser[$uid] = $row; } } @@ -601,14 +600,14 @@ class StaffAttendanceService $picked = null; foreach ($roles as $role) { - $slug = strtolower((string) ($role['role_slug'] ?? $role['role_name'] ?? '')); - if (! in_array($slug, $excludeSlugs, true)) { + $slug = strtolower((string)($role['role_slug'] ?? $role['role_name'] ?? '')); + if (!in_array($slug, $excludeSlugs, true)) { $picked = $role; break; } } - if (! $picked) { + if (!$picked) { continue; } @@ -619,9 +618,8 @@ class StaffAttendanceService } usort($adminsGrid, function ($a, $b) { - $an = trim(($a['firstname'] ?? '').' '.($a['lastname'] ?? '')); - $bn = trim(($b['firstname'] ?? '').' '.($b['lastname'] ?? '')); - + $an = trim(($a['firstname'] ?? '') . ' ' . ($a['lastname'] ?? '')); + $bn = trim(($b['firstname'] ?? '') . ' ' . ($b['lastname'] ?? '')); return strcasecmp($an, $bn); }); @@ -635,20 +633,20 @@ class StaffAttendanceService public function saveAdmins(Authenticatable $user, array $data): array { - $date = (string) $data['date']; - $semester = (string) $data['semester']; - $schoolYear = (string) $data['school_year']; - $admins = (array) ($data['admins'] ?? $data['staff'] ?? []); + $date = (string)$data['date']; + $semester = (string)$data['semester']; + $schoolYear = (string)$data['school_year']; + $admins = (array)($data['admins'] ?? $data['staff'] ?? []); $allowedStatuses = ['present', 'absent', 'late']; $excludedRoleSlugs = ['parent', 'guest', 'teacher', 'teacher_assistant']; DB::transaction(function () use ($admins, $date, $semester, $schoolYear, $allowedStatuses, $excludedRoleSlugs) { foreach ($admins as $uid => $row) { - $uid = (int) $uid; - $status = strtolower(trim((string) ($row['status'] ?? ''))); - $reason = trim((string) ($row['reason'] ?? '')); - $roleName = (string) ($row['role_name'] ?? ''); - $roleSlug = strtolower(str_replace(['-', ' '], '_', (string) ($row['role_slug'] ?? $roleName))); + $uid = (int)$uid; + $status = strtolower(trim((string)($row['status'] ?? ''))); + $reason = trim((string)($row['reason'] ?? '')); + $roleName = (string)($row['role_name'] ?? ''); + $roleSlug = strtolower(str_replace(['-', ' '], '_', (string)($row['role_slug'] ?? $roleName))); if (in_array($roleSlug, $excludedRoleSlugs, true)) { continue; @@ -661,11 +659,10 @@ class StaffAttendanceService ->where('semester', $semester) ->where('school_year', $schoolYear) ->delete(); - continue; } - if (! in_array($status, $allowedStatuses, true)) { + if (!in_array($status, $allowedStatuses, true)) { continue; } @@ -695,13 +692,13 @@ class StaffAttendanceService public function saveCell(Authenticatable $user, array $data): array { - $date = (string) $data['date']; - $status = (string) ($data['status'] ?? ''); - $targetId = (int) $data['user_id']; - $roleName = trim((string) ($data['role_name'] ?? '')); - $semester = (string) $data['semester']; - $schoolYear = (string) $data['school_year']; - $reason = trim((string) ($data['reason'] ?? '')); + $date = (string)$data['date']; + $status = (string)($data['status'] ?? ''); + $targetId = (int)$data['user_id']; + $roleName = trim((string)($data['role_name'] ?? '')); + $semester = (string)$data['semester']; + $schoolYear = (string)$data['school_year']; + $reason = trim((string)($data['reason'] ?? '')); if ($status === '') { DB::table('staff_attendance') @@ -735,9 +732,9 @@ class StaffAttendanceService public function monthCsv(?string $semester, ?string $schoolYear, ?string $scope): StreamedResponse { - $semester = $semester ?: (string) $this->configuration->getConfig('semester'); - $schoolYear = $schoolYear ?: (string) $this->configuration->getConfig('school_year'); - $scope = strtolower((string) $scope); + $semester = $semester ?: (string)$this->configuration->getConfig('semester'); + $schoolYear = $schoolYear ?: (string)$this->configuration->getConfig('school_year'); + $scope = strtolower((string)$scope); [$rangeStart, $rangeEnd] = $this->semesterRangeService->getSchoolYearRange($schoolYear); $semesterNorm = $this->semesterRangeService->normalizeSemester($semester); @@ -751,9 +748,9 @@ class StaffAttendanceService $daysList = $this->semesterRangeService->buildSundayList($rangeStart, $rangeEnd); $filename = ($scope === 'admins' ? 'admin_attendance_' : 'teacher_attendance_') - .$semester.'_'.str_replace('/', '-', $schoolYear).'.csv'; + . $semester . '_' . str_replace('/', '-', $schoolYear) . '.csv'; - return response()->streamDownload(function () use ($schoolYear, $scope, $semesterNorm, $rangeStart, $rangeEnd) { + return response()->streamDownload(function () use ($semester, $schoolYear, $scope, $daysList, $semesterNorm, $rangeStart, $rangeEnd) { $out = fopen('php://output', 'w'); if ($scope === 'admins') { @@ -773,13 +770,12 @@ class StaffAttendanceService fputcsv($out, [ $row->user_id, $row->date, - strtoupper(substr((string) $row->status, 0, 1)), + strtoupper(substr((string)$row->status, 0, 1)), $row->reason, ]); } fclose($out); - return; } @@ -799,7 +795,7 @@ class StaffAttendanceService fputcsv($out, [ $row->user_id, $row->date, - strtoupper(substr((string) $row->status, 0, 1)), + strtoupper(substr((string)$row->status, 0, 1)), $row->reason, ]); } diff --git a/app/Services/Attendance/StudentAttendanceWriterService.php b/app/Services/Attendance/StudentAttendanceWriterService.php index e6758416..1f81b5d9 100644 --- a/app/Services/Attendance/StudentAttendanceWriterService.php +++ b/app/Services/Attendance/StudentAttendanceWriterService.php @@ -70,7 +70,7 @@ class StudentAttendanceWriterService public function resolveStudentSchoolId(int $studentId, ?string $studentSchoolId = null): string { - $studentSchoolId = trim((string) $studentSchoolId); + $studentSchoolId = trim((string)$studentSchoolId); if ($studentSchoolId !== '') { return $studentSchoolId; @@ -78,25 +78,25 @@ class StudentAttendanceWriterService $studentRow = $this->student->query()->select('school_id')->find($studentId); - if (! $studentRow || empty($studentRow->school_id)) { + if (!$studentRow || empty($studentRow->school_id)) { throw new RuntimeException('Student school ID not found.'); } - return (string) $studentRow->school_id; + return (string)$studentRow->school_id; } public function saveOrUpdateStudentAttendance(array $payload): array { - $classSectionId = (int) $payload['class_section_id']; - $studentId = (int) $payload['student_id']; + $classSectionId = (int)$payload['class_section_id']; + $studentId = (int)$payload['student_id']; $studentSchoolId = $this->resolveStudentSchoolId($studentId, $payload['school_id'] ?? null); - $status = strtolower((string) $payload['status']); + $status = strtolower((string)$payload['status']); $reason = $payload['reason'] ?? null; $reported = $payload['is_reported'] ?? null; - $semester = (string) $payload['semester']; - $schoolYear = (string) $payload['school_year']; - $date = (string) $payload['date']; - $classId = (int) $payload['class_id']; + $semester = (string)$payload['semester']; + $schoolYear = (string)$payload['school_year']; + $date = (string)$payload['date']; + $classId = (int)$payload['class_id']; $userId = $payload['user_id'] ?? null; $existing = AttendanceData::query() @@ -110,7 +110,7 @@ class StudentAttendanceWriterService $oldStatus = $existing->status; $this->updateAttendanceData( - (int) $existing->id, + (int)$existing->id, $status, $reason, $reported, @@ -131,7 +131,7 @@ class StudentAttendanceWriterService return [ 'mode' => 'updated', - 'attendance_id' => (int) $existing->id, + 'attendance_id' => (int)$existing->id, 'old_status' => $oldStatus, 'new_status' => $status, 'school_id' => $studentSchoolId, @@ -172,10 +172,10 @@ class StudentAttendanceWriterService return [ 'mode' => 'created', - 'attendance_id' => (int) ($created->id ?? 0), + 'attendance_id' => (int)($created->id ?? 0), 'old_status' => null, 'new_status' => $status, 'school_id' => $studentSchoolId, ]; } -} +} \ No newline at end of file diff --git a/app/Services/Attendance/TeacherAttendanceSubmissionService.php b/app/Services/Attendance/TeacherAttendanceSubmissionService.php index 2b2c1ef5..48798821 100644 --- a/app/Services/Attendance/TeacherAttendanceSubmissionService.php +++ b/app/Services/Attendance/TeacherAttendanceSubmissionService.php @@ -31,7 +31,7 @@ class TeacherAttendanceSubmissionService callable $currentSemester, callable $currentSchoolYear ): array { - $rawSection = trim((string) $data['class_section_id']); + $rawSection = trim((string)$data['class_section_id']); if ($rawSection === '') { throw new RuntimeException('Missing or invalid class section.'); @@ -42,36 +42,36 @@ class TeacherAttendanceSubmissionService ->where('class_section_id', $rawSection) ->first(); - if (! $sectionRow && ctype_digit($rawSection)) { + if (!$sectionRow && ctype_digit($rawSection)) { $sectionRow = DB::table('classSection') ->select('id', 'class_id', 'class_section_id') - ->where('id', (int) $rawSection) + ->where('id', (int)$rawSection) ->first(); } - if (! $sectionRow) { + if (!$sectionRow) { throw new RuntimeException('Invalid class section.'); } - $classSectionId = (int) $sectionRow->class_section_id; - $classSectionPk = (int) ($sectionRow->id ?? 0); + $classSectionId = (int)$sectionRow->class_section_id; + $classSectionPk = (int)($sectionRow->id ?? 0); $alsoSectionId = ($classSectionPk > 0 && $classSectionPk !== $classSectionId) ? $classSectionPk : null; - $classId = (int) $sectionRow->class_id; + $classId = (int)$sectionRow->class_id; $attendanceData = $data['attendance'] ?? []; $teachersData = $data['teachers'] ?? []; - if (empty($attendanceData) || ! is_array($attendanceData)) { + if (empty($attendanceData) || !is_array($attendanceData)) { throw new RuntimeException('No student attendance data provided.'); } - if (empty($teachersData) || ! is_array($teachersData)) { + if (empty($teachersData) || !is_array($teachersData)) { throw new RuntimeException('No teacher attendance data provided.'); } $rawDate = $data['date'] ?? now()->toDateString(); $attendDate = Carbon::parse($rawDate)->toDateString(); - $semester = (string) $currentSemester(); - $schoolYear = (string) $currentSchoolYear(); + $semester = (string)$currentSemester(); + $schoolYear = (string)$currentSchoolYear(); $dayRow = AttendanceDay::query() ->where('class_section_id', $classSectionId) @@ -94,7 +94,7 @@ class TeacherAttendanceSubmissionService 'school_year' => $schoolYear, ]; - if (! $this->attendancePolicyService->canEditDay($dayPolicyRow, $currentUser)) { + if (!$this->attendancePolicyService->canEditDay($dayPolicyRow, $currentUser)) { throw new RuntimeException('Attendance is locked for your role.'); } @@ -107,7 +107,7 @@ class TeacherAttendanceSubmissionService $existingByStudent = []; foreach ($existingRows as $row) { - $existingByStudent[(int) $row->student_id] = $row->toArray(); + $existingByStudent[(int)$row->student_id] = $row->toArray(); } $allowedStatuses = ['present', 'absent', 'late']; @@ -129,10 +129,10 @@ class TeacherAttendanceSubmissionService } foreach ($assignedTeachers as $teacher) { - $teacherId = (int) $teacher['teacher_id']; - $status = strtolower((string) ($teachersData[$teacherId]['status'] ?? '')); + $teacherId = (int)$teacher['teacher_id']; + $status = strtolower((string)($teachersData[$teacherId]['status'] ?? '')); - if (! in_array($status, $allowedStatuses, true)) { + if (!in_array($status, $allowedStatuses, true)) { throw new RuntimeException('Please fill teacher attendance for all assigned teachers.'); } } @@ -168,13 +168,13 @@ class TeacherAttendanceSubmissionService ); foreach ($assignedTeachers as $teacher) { - $teacherId = (int) $teacher['teacher_id']; - $position = strtolower((string) ($teacher['position'] ?? 'main')); + $teacherId = (int)$teacher['teacher_id']; + $position = strtolower((string)($teacher['position'] ?? 'main')); $position = $position === 'ta' ? 'ta' : 'main'; $staffPayload = [ 'role_name' => 'Teacher', - 'status' => strtolower((string) ($teachersData[$teacherId]['status'] ?? 'present')), + 'status' => strtolower((string)($teachersData[$teacherId]['status'] ?? 'present')), 'reason' => ($teachersData[$teacherId]['reason'] ?? null) ?: null, 'updated_at' => now(), 'created_at' => now(), @@ -198,9 +198,9 @@ class TeacherAttendanceSubmissionService } foreach ($attendanceData as $row) { - $studentId = (int) ($row['student_id'] ?? 0); - $status = strtolower(trim((string) ($row['status'] ?? ''))); - $reason = trim((string) ($row['reason'] ?? '')); + $studentId = (int)($row['student_id'] ?? 0); + $status = strtolower(trim((string)($row['status'] ?? ''))); + $reason = trim((string)($row['reason'] ?? '')); $existing = $existingByStudent[$studentId] ?? null; if ($isTeacher && $existing) { diff --git a/app/Services/AttendanceManagement/AttendanceManagementService.php b/app/Services/AttendanceManagement/AttendanceManagementService.php index 1a73bde3..5c9226c6 100644 --- a/app/Services/AttendanceManagement/AttendanceManagementService.php +++ b/app/Services/AttendanceManagement/AttendanceManagementService.php @@ -7,21 +7,17 @@ use App\Models\LateSlipLog; use App\Models\Student; use App\Models\User; use Carbon\Carbon; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; class AttendanceManagementService { public const STATUS_PRESENT = 'present'; - public const STATUS_ABSENT_PENDING = 'absent_pending_verification'; - public const STATUS_ABSENT = 'absent'; - public const STATUS_LATE = 'late'; - public const STATUS_EARLY_DISMISSAL = 'early_dismissal'; - public const STATUS_LATE_WITHOUT_SLIP = 'late_without_slip'; public function dashboard(array $filters = []): array @@ -208,7 +204,6 @@ class AttendanceManagementService if ($person['type'] === 'student' && $status === self::STATUS_LATE) { $row['late_slip'] = $this->printLateSlip($row, $actor); } - return $row; } @@ -258,7 +253,6 @@ class AttendanceManagementService if (($data['exit_method'] ?? '') === 'manual_exit') { $this->recordBadgeException((int) $id, $person, $exitAt, 'manual exit entry', $badgeExceptions, $actor, $data['notes'] ?? null); } - return $row; } @@ -298,7 +292,6 @@ class AttendanceManagementService ]; $id = DB::table('attendance_management_events')->insertGetId($row); $row['id'] = $id; - return $row; } @@ -319,7 +312,6 @@ class AttendanceManagementService $update['report_status'] = $this->normalizeReportStatus($data['report_status']); } DB::table('attendance_management_events')->where('id', $id)->update($update); - return (array) DB::table('attendance_management_events')->where('id', $id)->first(); } @@ -355,7 +347,6 @@ class AttendanceManagementService 'final_decision' => 'Late slip reprinted', 'updated_at' => now(), ]); - return $row; } @@ -376,24 +367,12 @@ class AttendanceManagementService $student = null; $user = null; - if ($type === 'student' && $id > 0) { - $student = Student::query()->find($id); - } - if (in_array($type, ['staff', 'user', 'teacher', 'administrator'], true) && $id > 0) { - $user = User::query()->find($id); - } - if (! $student && $badge !== '') { - $student = Student::query()->where('rfid_tag', $badge)->first(); - } - if (! $student && ! $user && $badge !== '') { - $user = User::query()->where('rfid_tag', $badge)->first(); - } - if (! $student && ! $user && $id > 0) { - $student = Student::query()->find($id); - } - if (! $student && ! $user && $id > 0) { - $user = User::query()->find($id); - } + if ($type === 'student' && $id > 0) $student = Student::query()->find($id); + if (in_array($type, ['staff', 'user', 'teacher', 'administrator'], true) && $id > 0) $user = User::query()->find($id); + if (! $student && $badge !== '') $student = Student::query()->where('rfid_tag', $badge)->first(); + if (! $student && ! $user && $badge !== '') $user = User::query()->where('rfid_tag', $badge)->first(); + if (! $student && ! $user && $id > 0) $student = Student::query()->find($id); + if (! $student && ! $user && $id > 0) $user = User::query()->find($id); if ($student) { return [ @@ -418,7 +397,6 @@ class AttendanceManagementService if ($name === '') { throw new \InvalidArgumentException('Person could not be resolved. Provide person_id, badge_id, or person_name.'); } - return [ 'type' => $type !== '' ? $type : 'visitor', 'id' => $id > 0 ? $id : null, @@ -441,7 +419,6 @@ class AttendanceManagementService 'admin_name' => $actor ? trim(($actor->firstname ?? '').' '.($actor->lastname ?? '')) : 'System', ]; $logged = LateSlipLog::logSlip($payload, $actor?->id); - return [ 'printed' => $logged, 'slip_number' => 'AME-'.($event['id'] ?? time()), @@ -481,16 +458,9 @@ class AttendanceManagementService $absence = (clone $q)->where('attendance_status', self::STATUS_ABSENT)->count(); $late = (clone $q)->whereIn('attendance_status', [self::STATUS_LATE, self::STATUS_LATE_WITHOUT_SLIP])->count(); $ed = (clone $q)->where('attendance_status', self::STATUS_EARLY_DISMISSAL)->count(); - if ($newStatus === self::STATUS_ABSENT) { - $absence++; - } - if (in_array($newStatus, [self::STATUS_LATE, self::STATUS_LATE_WITHOUT_SLIP], true)) { - $late++; - } - if ($newStatus === self::STATUS_EARLY_DISMISSAL) { - $ed++; - } - + if ($newStatus === self::STATUS_ABSENT) $absence++; + if (in_array($newStatus, [self::STATUS_LATE, self::STATUS_LATE_WITHOUT_SLIP], true)) $late++; + if ($newStatus === self::STATUS_EARLY_DISMISSAL) $ed++; return ['absence_count' => $absence, 'late_count' => $late, 'early_dismissal_count' => $ed]; } @@ -558,7 +528,6 @@ class AttendanceManagementService private function schoolStartFor(Carbon $date): Carbon { $configured = Configuration::getConfigValueByKey('school_start_time') ?: config('attendance.school_start_time', '09:00:00'); - return Carbon::parse($date->toDateString().' '.$configured, $date->timezone); } @@ -647,20 +616,12 @@ class AttendanceManagementService })); } - private function dateTime($value): Carbon - { - return $value instanceof Carbon ? $value : Carbon::parse((string) $value); - } - - private function dateOnly($value): string - { - return Carbon::parse((string) $value)->toDateString(); - } + private function dateTime($value): Carbon { return $value instanceof Carbon ? $value : Carbon::parse((string) $value); } + private function dateOnly($value): string { return Carbon::parse((string) $value)->toDateString(); } private function normalizeReportStatus($value): string { $v = strtolower(str_replace(['-', ' '], '_', trim((string) $value))); - return in_array($v, ['reported', 'not_reported', 'pending_clarification'], true) ? $v : 'pending_clarification'; } @@ -680,61 +641,30 @@ class AttendanceManagementService private function combinationCode(int $abs, int $late, int $ed, int $badge): string { $parts = []; - if ($abs > 0) { - $parts[] = min($abs, 5).'ABS'; - } - if ($late > 0) { - $parts[] = min($late, 5).'Late'; - } - if ($ed > 0) { - $parts[] = min($ed, 3).'ED'; - } - if ($badge > 0) { - $parts[] = min($badge, 5).'Badge Exceptions'; - } - + if ($abs > 0) $parts[] = min($abs, 5).'ABS'; + if ($late > 0) $parts[] = min($late, 5).'Late'; + if ($ed > 0) $parts[] = min($ed, 3).'ED'; + if ($badge > 0) $parts[] = min($badge, 5).'Badge Exceptions'; return $parts ? implode(' + ', $parts) : 'Clear'; } private function riskLevel(int $abs, int $late, int $ed, int $badge): string { - if ($abs >= 5 && $late >= 5) { - return 'severe'; - } - if ($abs >= 5 || $late >= 5) { - return 'critical'; - } - if ($abs + $late + $ed + $badge >= 6 || $abs >= 4 || $late >= 4) { - return 'very_high'; - } - if ($abs + $late + $ed + $badge >= 4 || $abs >= 3 || $late >= 3 || $badge >= 4) { - return 'high'; - } - if ($abs + $late + $ed + $badge >= 2 || $badge >= 2) { - return 'medium'; - } - + if ($abs >= 5 && $late >= 5) return 'severe'; + if ($abs >= 5 || $late >= 5) return 'critical'; + if ($abs + $late + $ed + $badge >= 6 || $abs >= 4 || $late >= 4) return 'very_high'; + if ($abs + $late + $ed + $badge >= 4 || $abs >= 3 || $late >= 3 || $badge >= 4) return 'high'; + if ($abs + $late + $ed + $badge >= 2 || $badge >= 2) return 'medium'; return 'low'; } private function actionNeeded(string $status, string $reportStatus, int $badgeCount): string { - if ($badgeCount >= 5) { - return 'Leadership review for badge compliance'; - } - if ($badgeCount >= 4) { - return 'Formal badge follow-up required'; - } - if ($status === self::STATUS_LATE && $reportStatus !== 'reported') { - return 'Print late slip and contact parent or staff'; - } - if ($status === self::STATUS_ABSENT && $reportStatus !== 'reported') { - return 'Same-day contact required'; - } - if ($status === self::STATUS_EARLY_DISMISSAL && $reportStatus !== 'reported') { - return 'Verify authorization and contact guardian/supervisor'; - } - + if ($badgeCount >= 5) return 'Leadership review for badge compliance'; + if ($badgeCount >= 4) return 'Formal badge follow-up required'; + if ($status === self::STATUS_LATE && $reportStatus !== 'reported') return 'Print late slip and contact parent or staff'; + if ($status === self::STATUS_ABSENT && $reportStatus !== 'reported') return 'Same-day contact required'; + if ($status === self::STATUS_EARLY_DISMISSAL && $reportStatus !== 'reported') return 'Verify authorization and contact guardian/supervisor'; return 'Record and monitor'; } diff --git a/app/Services/AttendanceTracking/AttendanceCaseQueryService.php b/app/Services/AttendanceTracking/AttendanceCaseQueryService.php index a0ba324e..2afe6d83 100644 --- a/app/Services/AttendanceTracking/AttendanceCaseQueryService.php +++ b/app/Services/AttendanceTracking/AttendanceCaseQueryService.php @@ -17,7 +17,8 @@ class AttendanceCaseQueryService protected AttendanceTracking $attendanceTrackingModel, protected ViolationRuleEngineService $violationRuleEngine, protected AttendanceParentLookupService $parentLookupService - ) {} + ) { + } public function getStudentCase( int $studentId, @@ -31,16 +32,16 @@ class AttendanceCaseQueryService ?string $defaultSemester = null ): array { $student = $this->studentModel->query()->find($studentId); - if (! $student) { + if (!$student) { return [ 'success' => false, 'message' => 'Student not found', - 'status' => 404, + 'status' => 404, ]; } $student = $student->toArray(); - $student['name'] = trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')); + $student['name'] = trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')); $codeParam = strtoupper((string) ($codeParam ?? '')); $incidentDate = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) $incidentDate) ? (string) $incidentDate : ''; @@ -65,13 +66,13 @@ class AttendanceCaseQueryService } [$syStart, $syEnd] = $this->violationRuleEngine->deriveSchoolYearBounds($schoolYear ?: date('Y')); - $today = Carbon::today(); - $start = Carbon::parse($syStart)->startOfDay(); + $today = Carbon::today(); + $start = Carbon::parse($syStart)->startOfDay(); $rangeEnd = Carbon::parse(min($syEnd, $today->format('Y-m-d')))->startOfDay(); $windowWeeks = $this->violationRuleEngine->windowWeeksForViolationCode($codeParam); - $endYmd = $incidentDate !== '' ? $incidentDate : date('Y-m-d'); - $startYmd = $this->violationRuleEngine->activeWeekWindowStartYmd($endYmd, $windowWeeks, $schoolYear, $semester); + $endYmd = $incidentDate !== '' ? $incidentDate : date('Y-m-d'); + $startYmd = $this->violationRuleEngine->activeWeekWindowStartYmd($endYmd, $windowWeeks, $schoolYear, $semester); $studentIdValues = [(int) $studentId]; $studentCodeRaw = trim((string) ($student['student_code'] ?? $student['school_id'] ?? '')); @@ -107,7 +108,7 @@ class AttendanceCaseQueryService ]) ->where(function ($q) use ($studentIdValues, $studentCodeValues) { $q->whereIn('student_id', $studentIdValues); - if (! empty($studentCodeValues)) { + if (!empty($studentCodeValues)) { $q->orWhereIn('student_id', $studentCodeValues); } }) @@ -125,7 +126,7 @@ class AttendanceCaseQueryService if ($pendingOnly) { $this->violationRuleEngine->applyUnreportedAttendanceFilter($qb, $this->attendanceDataModel->getTable()); - if (! $includeNotified) { + if (!$includeNotified) { $qb->whereRaw("(LOWER(TRIM(COALESCE(is_notified, ''))) NOT IN ('yes','1'))"); } } @@ -141,21 +142,21 @@ class AttendanceCaseQueryService $attendanceRows = $qb->orderByDesc('date')->get()->toArray(); $data = [ - 'student' => $student, - 'attendance' => $attendanceRows, - 'violation_code' => $codeParam !== '' ? $codeParam : null, - 'violation_date' => $incidentDate, - 'violation_notified' => null, + 'student' => $student, + 'attendance' => $attendanceRows, + 'violation_code' => $codeParam !== '' ? $codeParam : null, + 'violation_date' => $incidentDate, + 'violation_notified' => null, 'show_violation_summary' => true, - 'school_year' => $schoolYear, - 'semester' => $semester, + 'school_year' => $schoolYear, + 'semester' => $semester, ]; - if ($data['violation_date'] === '' && ! empty($data['attendance'][0]['date'])) { + if ($data['violation_date'] === '' && !empty($data['attendance'][0]['date'])) { $data['violation_date'] = substr((string) $data['attendance'][0]['date'], 0, 10); } - if (! empty($data['attendance'][0]['is_notified'])) { + if (!empty($data['attendance'][0]['is_notified'])) { $data['violation_notified'] = $data['attendance'][0]['is_notified']; } @@ -171,7 +172,7 @@ class AttendanceCaseQueryService return [ 'success' => true, - 'data' => $data, + 'data' => $data, ]; } @@ -182,7 +183,7 @@ class AttendanceCaseQueryService ?string $defaultSemester = null ): array { $schoolYear = filled($schoolYearParam) ? (string) $schoolYearParam : (string) $defaultSchoolYear; - $semester = filled($semesterParam) ? (string) $semesterParam : (string) $defaultSemester; + $semester = filled($semesterParam) ? (string) $semesterParam : (string) $defaultSemester; $trackingData = $this->attendanceTrackingModel->query() ->where('school_year', $schoolYear) @@ -210,7 +211,7 @@ class AttendanceCaseQueryService if ($latest) { $schoolYear = (string) ($latest->school_year ?? $schoolYear); - $semester = (string) ($latest->semester ?? $semester); + $semester = (string) ($latest->semester ?? $semester); $trackingData = $this->attendanceTrackingModel->query() ->where('school_year', $schoolYear) @@ -228,9 +229,9 @@ class AttendanceCaseQueryService if (empty($trackingData)) { return [ - 'students' => [], - 'school_year' => $schoolYear, - 'semester' => $semester, + 'students' => [], + 'school_year' => $schoolYear, + 'semester' => $semester, 'show_actions' => false, ]; } @@ -257,9 +258,9 @@ class AttendanceCaseQueryService if (empty($trackingData)) { return [ - 'students' => [], - 'school_year' => $schoolYear, - 'semester' => $semester, + 'students' => [], + 'school_year' => $schoolYear, + 'semester' => $semester, 'show_actions' => false, ]; } @@ -288,12 +289,12 @@ class AttendanceCaseQueryService foreach ($rows as $row) { $sid = (int) ($row->student_id ?? 0); - if ($sid > 0 && ! isset($classByStudent[$sid])) { + if ($sid > 0 && !isset($classByStudent[$sid])) { $classByStudent[$sid] = [ - 'class_section_id' => $row->class_section_id ?? null, + 'class_section_id' => $row->class_section_id ?? null, 'class_section_name' => (string) ($row->class_section_name ?? ''), - 'class_id' => $row->class_id ?? null, - 'class_name' => (string) ($row->class_name ?? ''), + 'class_id' => $row->class_id ?? null, + 'class_name' => (string) ($row->class_name ?? ''), ]; } } @@ -303,7 +304,7 @@ class AttendanceCaseQueryService $mergedData = []; foreach ($trackingData as $row) { $sid = (int) ($row['student_id'] ?? 0); - if (! isset($studentMap[$sid])) { + if (!isset($studentMap[$sid])) { continue; } @@ -311,15 +312,15 @@ class AttendanceCaseQueryService if (isset($classByStudent[$sid])) { $merged['class_section_name'] = (string) ($classByStudent[$sid]['class_section_name'] ?? ''); - $merged['class_name'] = (string) ($classByStudent[$sid]['class_name'] ?? ''); - } elseif (! empty($merged['registration_grade'])) { + $merged['class_name'] = (string) ($classByStudent[$sid]['class_name'] ?? ''); + } elseif (!empty($merged['registration_grade'])) { $merged['grade'] = (string) $merged['registration_grade']; } try { $p = $this->parentLookupService->getPrimaryParentForStudent($sid); if ($p) { - $merged['parent_name'] = $p['parent_name'] ?? ''; + $merged['parent_name'] = $p['parent_name'] ?? ''; $merged['parent_email'] = $p['email'] ?? ''; $merged['parent_phone'] = $p['phone'] ?? ''; } @@ -330,9 +331,9 @@ class AttendanceCaseQueryService } return [ - 'students' => $mergedData, + 'students' => $mergedData, 'school_year' => $schoolYear, - 'semester' => $semester, + 'semester' => $semester, ]; } -} +} \ No newline at end of file diff --git a/app/Services/AttendanceTracking/AttendanceCommunicationSupportService.php b/app/Services/AttendanceTracking/AttendanceCommunicationSupportService.php index 5c475832..7e8cb2e8 100644 --- a/app/Services/AttendanceTracking/AttendanceCommunicationSupportService.php +++ b/app/Services/AttendanceTracking/AttendanceCommunicationSupportService.php @@ -10,7 +10,6 @@ use Illuminate\Support\Facades\DB; class AttendanceCommunicationSupportService { protected string $semester; - protected string $schoolYear; public function __construct( @@ -20,7 +19,7 @@ class AttendanceCommunicationSupportService protected AttendanceParentLookupService $parentLookupService, protected AttendanceEmailComposerService $emailComposerService ) { - $this->semester = (string) ($this->configModel->getConfig('semester') ?? ''); + $this->semester = (string) ($this->configModel->getConfig('semester') ?? ''); $this->schoolYear = (string) ($this->configModel->getConfig('school_year') ?? ''); } @@ -34,12 +33,12 @@ class AttendanceCommunicationSupportService return [ 'success' => false, 'message' => 'Missing student_id.', - 'status' => 422, + 'status' => 422, ]; } - $student = $this->studentModel->query()->find($studentId)?->toArray() ?? []; - $parent = $this->parentLookupService->getPrimaryParentForStudent($studentId); + $student = $this->studentModel->query()->find($studentId)?->toArray() ?? []; + $parent = $this->parentLookupService->getPrimaryParentForStudent($studentId); $secondary = $this->parentLookupService->getSecondaryParentForStudent($studentId, $this->schoolYear); $result = $this->emailComposerService->composePreview( @@ -53,7 +52,7 @@ class AttendanceCommunicationSupportService ); if (($result['success'] ?? false) && isset($result['data'])) { - $result['data']['semester'] = $this->semester; + $result['data']['semester'] = $this->semester; $result['data']['school_year'] = $this->schoolYear; } @@ -101,4 +100,4 @@ class AttendanceCommunicationSupportService ->values() ->all(); } -} +} \ No newline at end of file diff --git a/app/Services/AttendanceTracking/AttendanceEmailComposerService.php b/app/Services/AttendanceTracking/AttendanceEmailComposerService.php index 4ff13e2d..0ad29f50 100644 --- a/app/Services/AttendanceTracking/AttendanceEmailComposerService.php +++ b/app/Services/AttendanceTracking/AttendanceEmailComposerService.php @@ -4,25 +4,27 @@ namespace App\Services\AttendanceTracking; use App\Models\AttendanceEmailTemplate; use App\Support\MailHtml; +use Illuminate\Support\Str; class AttendanceEmailComposerService { public function __construct( protected AttendanceEmailTemplate $attendanceEmailTemplateModel - ) {} + ) { + } public function buildTemplateContext(array $violation, ?array $parent = null): array { $studentName = (string) ($violation['name'] ?? ''); - $incident = (string) ($violation['last_date'] ?? date('Y-m-d')); + $incident = (string) ($violation['last_date'] ?? date('Y-m-d')); return [ - '{{parent_name}}' => (string) ($parent['parent_name'] ?? 'Parent/Guardian'), - '{{student_name}}' => $studentName, - '{{incident_date}}' => $incident, - '{{school_phone}}' => '978-364-0219', + '{{parent_name}}' => (string) ($parent['parent_name'] ?? 'Parent/Guardian'), + '{{student_name}}' => $studentName, + '{{incident_date}}' => $incident, + '{{school_phone}}' => '978-364-0219', '{{voicemail_phone}}' => (string) ($parent['phone'] ?? '—'), - '{{class_time}}' => '10:00 AM', + '{{class_time}}' => '10:00 AM', ]; } @@ -40,7 +42,7 @@ class AttendanceEmailComposerService ->where('is_active', 1) ->first(); - if (! $row) { + if (!$row) { $row = $this->attendanceEmailTemplateModel->query() ->where('code', $code) ->where('variant', 'default') @@ -51,12 +53,12 @@ class AttendanceEmailComposerService $row = $row?->toArray(); } - if (! $row) { + if (!$row) { return null; } $subject = strtr($row['subject'], $context); - $body = strtr($row['body_html'], $context); + $body = strtr($row['body_html'], $context); return [$subject, $body]; } @@ -68,35 +70,35 @@ class AttendanceEmailComposerService public function pickVariant(string $code, ?string $globalVariantOverride = null): string { - if (! empty($globalVariantOverride)) { + if (!empty($globalVariantOverride)) { return $globalVariantOverride; } return match ($code) { 'ABS_2', 'ABS_2_IN3W' => 'no_answer', - default => 'default', + default => 'default', }; } public function buildFallbackAutoEmail(string $code, array $violation, string $parentName = ''): array { $subject = match ($code) { - 'ABS_1' => 'Attendance Notice: Unreported Absence', + 'ABS_1' => 'Attendance Notice: Unreported Absence', 'LATE_2' => 'Attendance Notice: Repeated Lateness', - default => 'Attendance Notice', + default => 'Attendance Notice', }; $studentName = (string) ($violation['name'] ?? ''); - $date = (string) ($violation['last_date'] ?? date('Y-m-d')); + $date = (string) ($violation['last_date'] ?? date('Y-m-d')); - $body = '

Dear '.($parentName ?: 'Parent/Guardian').'

' - ."

We'd like to inform you about your student's recent attendance:

" - .'
    ' - ."
  • Student: {$studentName}
  • " - .'
  • Issue: '.(string) ($violation['violation'] ?? '').'
  • ' - ."
  • As of: {$date}
  • " - .'
' - .'

If you have any questions, please contact the school office.

'; + $body = "

Dear " . ($parentName ?: 'Parent/Guardian') . "

" + . "

We'd like to inform you about your student's recent attendance:

" + . "
    " + . "
  • Student: {$studentName}
  • " + . "
  • Issue: " . (string) ($violation['violation'] ?? '') . "
  • " + . "
  • As of: {$date}
  • " + . "
" + . "

If you have any questions, please contact the school office.

"; return [$subject, $body]; } @@ -132,8 +134,7 @@ class AttendanceEmailComposerService static function ($m) { $url = $m[0]; $urlAttr = htmlspecialchars($url, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); - - return ''.$url.''; + return '' . $url . ''; }, $escaped ); @@ -141,9 +142,8 @@ class AttendanceEmailComposerService $paragraphs = preg_split("/\n{2,}/", $escaped); $paragraphs = array_map(static function ($p) { - $p = preg_replace("/\n/", '
', $p); - - return '

'.$p.'

'; + $p = preg_replace("/\n/", "
", $p); + return '

' . $p . '

'; }, $paragraphs); return implode("\n", $paragraphs); @@ -152,10 +152,10 @@ class AttendanceEmailComposerService public function renderAutoEmailFor(array $violation, ?array $parent = null): ?array { $code = (string) ($violation['violation_code'] ?? $violation['code'] ?? ''); - $ctx = $this->buildTemplateContext($violation, $parent); - $tpl = $this->renderTemplate($code, 'default', $ctx); + $ctx = $this->buildTemplateContext($violation, $parent); + $tpl = $this->renderTemplate($code, 'default', $ctx); - if (! $tpl) { + if (!$tpl) { return $this->buildFallbackAutoEmail($code, $violation, (string) ($parent['parent_name'] ?? '')); } @@ -176,21 +176,21 @@ class AttendanceEmailComposerService : date('Y-m-d'); $violation = [ - 'id' => $studentId, - 'name' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')), - 'last_date' => $lastDate, - 'violation' => $code, + 'id' => $studentId, + 'name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')), + 'last_date' => $lastDate, + 'violation' => $code, 'violation_code' => $code, ]; $ctx = $this->buildTemplateContext($violation, $primaryParent); $rendered = $this->renderTemplate($code, $variant, $ctx); - if (! $rendered) { + if (!$rendered) { return [ 'success' => false, 'message' => "Template not found for {$code} ({$variant}).", - 'status' => 404, + 'status' => 404, ]; } @@ -198,19 +198,19 @@ class AttendanceEmailComposerService return [ 'success' => true, - 'data' => [ - 'student_id' => $studentId, - 'student_name' => $violation['name'], - 'parent_email' => (string) ($primaryParent['email'] ?? ''), - 'parent_name' => (string) ($primaryParent['parent_name'] ?? ''), + 'data' => [ + 'student_id' => $studentId, + 'student_name' => $violation['name'], + 'parent_email' => (string) ($primaryParent['email'] ?? ''), + 'parent_name' => (string) ($primaryParent['parent_name'] ?? ''), 'secondary_email' => (string) ($secondaryParent['email'] ?? ''), - 'secondary_name' => (string) ($secondaryParent['parent_name'] ?? ''), - 'code' => $code, - 'variant' => $variant, - 'subject' => $subject, - 'body_html' => $body, - 'incident_date' => $lastDate, + 'secondary_name' => (string) ($secondaryParent['parent_name'] ?? ''), + 'code' => $code, + 'variant' => $variant, + 'subject' => $subject, + 'body_html' => $body, + 'incident_date' => $lastDate, ], ]; } -} +} \ No newline at end of file diff --git a/app/Services/AttendanceTracking/AttendanceMailerService.php b/app/Services/AttendanceTracking/AttendanceMailerService.php index d574ebaf..83f4bc5a 100644 --- a/app/Services/AttendanceTracking/AttendanceMailerService.php +++ b/app/Services/AttendanceTracking/AttendanceMailerService.php @@ -7,4 +7,4 @@ interface AttendanceMailerService public function send(string $to, string $subject, string $html): bool; public function queueAttendanceEvent(array $payload): void; -} +} \ No newline at end of file diff --git a/app/Services/AttendanceTracking/AttendanceNotificationLogService.php b/app/Services/AttendanceTracking/AttendanceNotificationLogService.php index fe153019..18d40397 100644 --- a/app/Services/AttendanceTracking/AttendanceNotificationLogService.php +++ b/app/Services/AttendanceTracking/AttendanceNotificationLogService.php @@ -10,7 +10,8 @@ class AttendanceNotificationLogService { public function __construct( protected ParentNotification $notificationModel - ) {} + ) { + } public function notificationAlreadySent( int $studentId, @@ -30,14 +31,13 @@ class AttendanceNotificationLogService ->where('incident_date', $ymd) ->where('channel', $channel); - if (! empty($to)) { + if (!empty($to)) { $query->where('to_address', $to); } return $query->exists(); } catch (Throwable $e) { - Log::debug('notificationAlreadySent(): '.$e->getMessage()); - + Log::debug('notificationAlreadySent(): ' . $e->getMessage()); return false; } } @@ -61,37 +61,37 @@ class AttendanceNotificationLogService ->whereDate('incident_date', $ymd) ->where('channel', $channel); - if (! empty($to)) { + if (!empty($to)) { $existingQuery->where('to_address', $to); } $existing = $existingQuery->orderByDesc('id')->first(); - if ($existing && ! empty($existing->id)) { + if ($existing && !empty($existing->id)) { $existing->update([ - 'subject' => $subject, - 'status' => $status, - 'response' => $response, - 'semester' => $semester, - 'school_year' => $schoolYear, - 'updated_at' => now(), + 'subject' => $subject, + 'status' => $status, + 'response' => $response, + 'semester' => $semester, + 'school_year' => $schoolYear, + 'updated_at' => now(), ]); } else { $this->notificationModel->query()->create([ - 'student_id' => $studentId, - 'code' => $code, + 'student_id' => $studentId, + 'code' => $code, 'incident_date' => $ymd, - 'channel' => $channel, - 'to_address' => $to, - 'subject' => $subject, - 'status' => $status, - 'response' => $response, - 'semester' => $semester, - 'school_year' => $schoolYear, + 'channel' => $channel, + 'to_address' => $to, + 'subject' => $subject, + 'status' => $status, + 'response' => $response, + 'semester' => $semester, + 'school_year' => $schoolYear, ]); } } catch (Throwable $e) { - Log::debug('logNotification(): '.$e->getMessage()); + Log::debug('logNotification(): ' . $e->getMessage()); } } } diff --git a/app/Services/AttendanceTracking/AttendanceNotificationWorkflowService.php b/app/Services/AttendanceTracking/AttendanceNotificationWorkflowService.php index 4b81d7e6..72969ac5 100644 --- a/app/Services/AttendanceTracking/AttendanceNotificationWorkflowService.php +++ b/app/Services/AttendanceTracking/AttendanceNotificationWorkflowService.php @@ -7,6 +7,7 @@ use App\Models\AttendanceTracking; use App\Models\Configuration; use App\Models\Student; use App\Models\StudentClass; +use Carbon\Carbon; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; use Throwable; @@ -14,7 +15,6 @@ use Throwable; class AttendanceNotificationWorkflowService { protected string $semester; - protected string $schoolYear; public function __construct( @@ -29,33 +29,33 @@ class AttendanceNotificationWorkflowService protected AttendanceEmailComposerService $emailComposerService, protected AttendanceNotificationLogService $notificationLogService ) { - $this->semester = (string) ($this->configModel->getConfig('semester') ?? ''); + $this->semester = (string) ($this->configModel->getConfig('semester') ?? ''); $this->schoolYear = (string) ($this->configModel->getConfig('school_year') ?? ''); } public function record(array $data): array { - $sid = (int) $data['student_id']; - $ymd = substr((string) $data['date'], 0, 10); - $semester = $data['semester'] ?? $this->semester; + $sid = (int) $data['student_id']; + $ymd = substr((string) $data['date'], 0, 10); + $semester = $data['semester'] ?? $this->semester; $schoolYear = $data['school_year'] ?? $this->schoolYear; - $subject = $data['subject_type'] ?? 'Absent'; + $subject = $data['subject_type'] ?? 'Absent'; $student = $this->studentModel->query()->find($sid)?->toArray() ?? []; $parentEmail = $data['parent_email'] ?? ''; - $parentName = $data['parent_name'] ?? ''; + $parentName = $data['parent_name'] ?? ''; - if (! $parentEmail) { + if (!$parentEmail) { $parent = $this->parentLookupService->getPrimaryParentForStudent($sid) ?? []; $parentEmail = $parent['email'] ?? ''; - $parentName = $parent['parent_name'] ?? ''; + $parentName = $parent['parent_name'] ?? ''; } - if (! $parentEmail) { + if (!$parentEmail) { return [ 'success' => false, 'message' => 'No parent email found for this student.', - 'status' => 422, + 'status' => 422, ]; } @@ -87,37 +87,37 @@ class AttendanceNotificationWorkflowService : []; $payload = [ - 'student_id' => $sid, - 'student' => $student, - 'parent' => ['email' => $parentEmail, 'name' => $parentName], - 'semester' => $semester, + 'student_id' => $sid, + 'student' => $student, + 'parent' => ['email' => $parentEmail, 'name' => $parentName], + 'semester' => $semester, 'school_year' => $schoolYear, - 'class' => $class, - 'now' => now()->toDateTimeString(), - 'date' => $ymd, - 'subject' => $subject, + 'class' => $class, + 'now' => now()->toDateTimeString(), + 'date' => $ymd, + 'subject' => $subject, 'consequence' => $consequence ?: 'follow_up', ]; try { $this->attendanceMailerService->queueAttendanceEvent($payload); - if ($row && ! empty($row['id']) && method_exists($this->attendanceTrackingModel, 'markAsNotified')) { + if ($row && !empty($row['id']) && method_exists($this->attendanceTrackingModel, 'markAsNotified')) { $this->attendanceTrackingModel->markAsNotified((int) $row['id']); } return [ 'success' => true, 'message' => 'Notification queued.', - 'data' => $payload, + 'data' => $payload, ]; } catch (Throwable $e) { - Log::error('Attendance record queue failed: '.$e->getMessage()); + Log::error('Attendance record queue failed: ' . $e->getMessage()); return [ 'success' => false, 'message' => $e->getMessage(), - 'status' => 500, + 'status' => 500, ]; } } @@ -132,32 +132,30 @@ class AttendanceNotificationWorkflowService $details = []; foreach ($toSend as $v) { - $sid = (int) ($v['id'] ?? 0); - $code = (string) ($v['violation_code'] ?? $v['code'] ?? ''); - $date = (string) ($v['last_date'] ?? ''); - $to = trim((string) ($v['parent_email'] ?? '')); + $sid = (int) ($v['id'] ?? 0); + $code = (string) ($v['violation_code'] ?? $v['code'] ?? ''); + $date = (string) ($v['last_date'] ?? ''); + $to = trim((string) ($v['parent_email'] ?? '')); $pname = (string) ($v['parent_name'] ?? ''); - if ($sid <= 0 || ! $code || ! $date || ! $to) { + if ($sid <= 0 || !$code || !$date || !$to) { $errors++; $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'missing data']; - continue; } if ($this->notificationLogService->notificationAlreadySent($sid, $code, $date, 'email', $to)) { $skipped++; $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'duplicate']; - continue; } - $parent = $this->parentLookupService->getPrimaryParentForStudent($sid); + $parent = $this->parentLookupService->getPrimaryParentForStudent($sid); $context = $this->emailComposerService->buildTemplateContext($v, $parent); $variant = $this->emailComposerService->pickVariant($code, $variantOverride); - $tpl = $this->emailComposerService->renderTemplate($code, $variant, $context); + $tpl = $this->emailComposerService->renderTemplate($code, $variant, $context); - if (! $tpl) { + if (!$tpl) { [$subject, $body] = $this->emailComposerService->buildFallbackAutoEmail($code, $v, $pname); } else { [$subject, $body] = $tpl; @@ -214,7 +212,7 @@ class AttendanceNotificationWorkflowService $this->semester, $this->schoolYear ); - $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'error: '.$e->getMessage()]; + $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'error: ' . $e->getMessage()]; } try { @@ -262,7 +260,7 @@ class AttendanceNotificationWorkflowService } } catch (Throwable $e) { $errors++; - $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'cc_error: '.$e->getMessage()]; + $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'cc_error: ' . $e->getMessage()]; } if ($anyOk) { @@ -279,13 +277,13 @@ class AttendanceNotificationWorkflowService } $allDates = []; - $absDates = array_map(fn ($d) => substr((string) $d, 0, 10), (array) ($v['absences'] ?? [])); + $absDates = array_map(fn ($d) => substr((string) $d, 0, 10), (array) ($v['absences'] ?? [])); $lateDates = array_map(fn ($d) => substr((string) $d, 0, 10), (array) ($v['lates'] ?? [])); - if (! empty($absDates)) { + if (!empty($absDates)) { $allDates = array_merge($allDates, $absDates); } - if (! empty($lateDates)) { + if (!empty($lateDates)) { $allDates = array_merge($allDates, $lateDates); } if (empty($allDates)) { @@ -305,29 +303,29 @@ class AttendanceNotificationWorkflowService return [ 'success' => true, - 'sent' => $sent, + 'sent' => $sent, 'skipped' => $skipped, - 'errors' => $errors, + 'errors' => $errors, 'details' => $details, ]; } public function sendEmailManual(array $data, array $violationDates = []): array { - $sid = (int) $data['student_id']; - $to = trim((string) $data['to']); - $subject = (string) $data['subject']; + $sid = (int) $data['student_id']; + $to = trim((string) $data['to']); + $subject = (string) $data['subject']; $bodyInput = (string) $data['body_html']; - $code = (string) $data['code']; - $variant = (string) ($data['variant'] ?? 'default'); + $code = (string) $data['code']; + $variant = (string) ($data['variant'] ?? 'default'); $ymdRaw = (string) ($data['incident_date'] ?? ''); - $ymd = $ymdRaw !== '' ? substr($ymdRaw, 0, 10) : ''; + $ymd = $ymdRaw !== '' ? substr($ymdRaw, 0, 10) : ''; $safeHtmlBody = $this->emailComposerService->normalizeBodyToHtml($bodyInput); $wrapped = $this->emailComposerService->renderWithEmailLayout($subject, $safeHtmlBody); - $semester = $this->semester ?: (string) ($this->configModel->getConfig('semester') ?? ''); + $semester = $this->semester ?: (string) ($this->configModel->getConfig('semester') ?? ''); $schoolYear = $this->schoolYear ?: (string) ($this->configModel->getConfig('school_year') ?? ''); try { @@ -356,7 +354,7 @@ class AttendanceNotificationWorkflowService $to2 = trim((string) ($sec['email'] ?? '')); if ($to2 !== '' && strcasecmp($to2, $to) !== 0) { - if (! $this->notificationLogService->notificationAlreadySent($sid, $code, $ymd, 'email', $to2)) { + if (!$this->notificationLogService->notificationAlreadySent($sid, $code, $ymd, 'email', $to2)) { $ok2 = $this->attendanceMailerService->send($to2, $subject, $wrapped); $this->notificationLogService->logNotification( @@ -378,11 +376,11 @@ class AttendanceNotificationWorkflowService } } - if (! $anyOk) { + if (!$anyOk) { return [ 'success' => false, 'message' => 'Failed to send email.', - 'status' => 500, + 'status' => 500, ]; } @@ -396,7 +394,7 @@ class AttendanceNotificationWorkflowService ); } - if (! empty($violationDates) && method_exists($this->attendanceDataModel, 'markReportedAndNotified')) { + if (!empty($violationDates) && method_exists($this->attendanceDataModel, 'markReportedAndNotified')) { $this->attendanceDataModel->markReportedAndNotified( $sid, $violationDates, @@ -408,12 +406,12 @@ class AttendanceNotificationWorkflowService return [ 'success' => true, 'message' => 'Email sent successfully.', - 'data' => [ - 'student_id' => $sid, - 'to' => $to, - 'secondary_to' => $to2 ?? null, - 'subject' => $subject, - 'variant' => $variant, + 'data' => [ + 'student_id' => $sid, + 'to' => $to, + 'secondary_to' => $to2 ?? null, + 'subject' => $subject, + 'variant' => $variant, 'incident_date' => $ymd, ], ]; @@ -433,19 +431,19 @@ class AttendanceNotificationWorkflowService return [ 'success' => false, - 'message' => 'Error: '.$e->getMessage(), - 'status' => 500, + 'message' => 'Error: ' . $e->getMessage(), + 'status' => 500, ]; } } public function saveNotificationNote(array $data): array { - $sid = (int) $data['student_id']; - $code = (string) $data['code']; - $note = trim((string) $data['note']); + $sid = (int) $data['student_id']; + $code = (string) $data['code']; + $note = trim((string) $data['note']); $ymdRaw = (string) ($data['incident_date'] ?? ''); - $ymd = $ymdRaw !== '' ? substr($ymdRaw, 0, 10) : ''; + $ymd = $ymdRaw !== '' ? substr($ymdRaw, 0, 10) : ''; try { $day = $ymd !== '' ? $ymd : date('Y-m-d'); @@ -457,11 +455,11 @@ class AttendanceNotificationWorkflowService ->where('school_year', $this->schoolYear) ->where('date', '>=', $start) ->where('date', '<', $end) - ->where('reason', 'like', '%'.$code.'%') + ->where('reason', 'like', '%' . $code . '%') ->orderByDesc('date') ->first(); - if (! $row) { + if (!$row) { $row = $this->attendanceTrackingModel->query() ->where('student_id', $sid) ->where('semester', $this->semester) @@ -472,28 +470,28 @@ class AttendanceNotificationWorkflowService ->first(); } - if ($row && ! empty($row->id)) { + if ($row && !empty($row->id)) { DB::table($this->attendanceTrackingModel->getTable()) ->where('id', (int) $row->id) ->update([ 'notif_counter' => DB::raw('COALESCE(notif_counter,0)+1'), - 'note' => $note, - 'is_notified' => 1, - 'updated_at' => now(), + 'note' => $note, + 'is_notified' => 1, + 'updated_at' => now(), ]); } else { $this->attendanceTrackingModel->query()->create([ - 'student_id' => $sid, - 'date' => $start, - 'is_reported' => 0, - 'reason' => $code, - 'is_notified' => 1, + 'student_id' => $sid, + 'date' => $start, + 'is_reported' => 0, + 'reason' => $code, + 'is_notified' => 1, 'notif_counter' => 1, - 'semester' => $this->semester, - 'school_year' => $this->schoolYear, - 'note' => $note, - 'created_at' => now(), - 'updated_at' => now(), + 'semester' => $this->semester, + 'school_year' => $this->schoolYear, + 'note' => $note, + 'created_at' => now(), + 'updated_at' => now(), ]); } @@ -504,9 +502,9 @@ class AttendanceNotificationWorkflowService } catch (Throwable $e) { return [ 'success' => false, - 'message' => 'Failed to save note: '.$e->getMessage(), - 'status' => 500, + 'message' => 'Failed to save note: ' . $e->getMessage(), + 'status' => 500, ]; } } -} +} \ No newline at end of file diff --git a/app/Services/AttendanceTracking/AttendanceParentLookupService.php b/app/Services/AttendanceTracking/AttendanceParentLookupService.php index 60d7d1c6..dfebc7bc 100644 --- a/app/Services/AttendanceTracking/AttendanceParentLookupService.php +++ b/app/Services/AttendanceTracking/AttendanceParentLookupService.php @@ -16,15 +16,15 @@ class AttendanceParentLookupService ->where('s.id', $studentId) ->first(); - if (! $row || empty($row->user_id)) { + if (!$row || empty($row->user_id)) { return null; } return [ - 'user_id' => (int) $row->user_id, - 'email' => (string) ($row->email ?? ''), + 'user_id' => (int) $row->user_id, + 'email' => (string) ($row->email ?? ''), 'parent_name' => (string) ($row->parent_name ?? ''), - 'phone' => $row->cellphone ?? null, + 'phone' => $row->cellphone ?? null, ]; } @@ -36,11 +36,11 @@ class AttendanceParentLookupService ->where('id', $studentId) ->first(); - if (! $stu) { + if (!$stu) { return null; } - $primaryId = (int) ($stu->parent_id ?? 0); + $primaryId = (int) ($stu->parent_id ?? 0); $schoolYear = (string) ($stu->school_year ?? $fallbackSchoolYear ?? ''); $pb = DB::table('parents')->where('firstparent_id', $primaryId); @@ -49,7 +49,7 @@ class AttendanceParentLookupService } $pRow = $pb->orderByDesc('updated_at')->first(); - if (! $pRow) { + if (!$pRow) { return null; } @@ -60,12 +60,12 @@ class AttendanceParentLookupService ->where('id', $secondId) ->first(); - if ($u2 && ! empty($u2->email)) { + if ($u2 && !empty($u2->email)) { return [ - 'user_id' => (int) $u2->id, - 'email' => (string) $u2->email, - 'parent_name' => trim(($u2->firstname ?? '').' '.($u2->lastname ?? '')), - 'phone' => (string) ($u2->cellphone ?? ''), + 'user_id' => (int) $u2->id, + 'email' => (string) $u2->email, + 'parent_name' => trim(($u2->firstname ?? '') . ' ' . ($u2->lastname ?? '')), + 'phone' => (string) ($u2->cellphone ?? ''), ]; } } @@ -73,18 +73,18 @@ class AttendanceParentLookupService $fallbackEmail = (string) ($pRow->secondparent_email ?? ''); $fallbackPhone = (string) ($pRow->secondparent_phone ?? ''); $fallbackFirst = (string) ($pRow->secondparent_firstname ?? ''); - $fallbackLast = (string) ($pRow->secondparent_lastname ?? ''); + $fallbackLast = (string) ($pRow->secondparent_lastname ?? ''); if ($fallbackEmail || $fallbackPhone || $fallbackFirst || $fallbackLast) { return [ - 'user_id' => $secondId ?: null, - 'email' => $fallbackEmail, - 'parent_name' => trim($fallbackFirst.' '.$fallbackLast) ?: null, - 'phone' => $fallbackPhone, + 'user_id' => $secondId ?: null, + 'email' => $fallbackEmail, + 'parent_name' => trim($fallbackFirst . ' ' . $fallbackLast) ?: null, + 'phone' => $fallbackPhone, ]; } } catch (Throwable $e) { - Log::error('getSecondaryParentForStudent() failed: '.$e->getMessage()); + Log::error('getSecondaryParentForStudent() failed: ' . $e->getMessage()); } return null; @@ -96,7 +96,7 @@ class AttendanceParentLookupService return [ 'success' => false, 'message' => 'Missing student_id', - 'status' => 422, + 'status' => 422, ]; } @@ -106,15 +106,15 @@ class AttendanceParentLookupService ->where('id', $studentId) ->first(); - if (! $stu) { + if (!$stu) { return [ 'success' => false, 'message' => 'Student not found', - 'status' => 404, + 'status' => 404, ]; } - $primaryId = (int) $stu->parent_id; + $primaryId = (int) $stu->parent_id; $schoolYear = $stu->school_year ?: $currentSchoolYear; $u1 = DB::table('users') @@ -123,39 +123,39 @@ class AttendanceParentLookupService ->first(); $primary = $u1 ? [ - 'id' => (int) $u1->id, + 'id' => (int) $u1->id, 'firstname' => (string) $u1->firstname, - 'lastname' => (string) $u1->lastname, - 'email' => (string) $u1->email, + 'lastname' => (string) $u1->lastname, + 'email' => (string) $u1->email, 'cellphone' => (string) $u1->cellphone, ] : null; $secondaryRaw = $this->getSecondaryParentForStudent($studentId, $schoolYear); $secondary = $secondaryRaw ? [ - 'id' => $secondaryRaw['user_id'] ?? null, + 'id' => $secondaryRaw['user_id'] ?? null, 'firstname' => null, - 'lastname' => null, - 'email' => $secondaryRaw['email'] ?? '', + 'lastname' => null, + 'email' => $secondaryRaw['email'] ?? '', 'cellphone' => $secondaryRaw['phone'] ?? '', - 'name' => $secondaryRaw['parent_name'] ?? '', + 'name' => $secondaryRaw['parent_name'] ?? '', ] : null; return [ 'success' => true, - 'data' => [ - 'primary' => $primary, + 'data' => [ + 'primary' => $primary, 'secondary' => $secondary, ], ]; } catch (Throwable $e) { - Log::error('parentsInfo() failed: '.$e->getMessage()); + Log::error('parentsInfo() failed: ' . $e->getMessage()); return [ 'success' => false, 'message' => 'Server error', - 'status' => 500, + 'status' => 500, ]; } } -} +} \ No newline at end of file diff --git a/app/Services/AttendanceTracking/AttendancePendingViolationService.php b/app/Services/AttendanceTracking/AttendancePendingViolationService.php index b7c02912..47160df7 100644 --- a/app/Services/AttendanceTracking/AttendancePendingViolationService.php +++ b/app/Services/AttendanceTracking/AttendancePendingViolationService.php @@ -13,7 +13,8 @@ class AttendancePendingViolationService protected AttendanceData $attendanceDataModel, protected ViolationRuleEngineService $violationRuleEngine, protected AttendanceViolationStudentResolverService $studentResolverService - ) {} + ) { + } public function getPendingViolations( string $defaultSchoolYear, @@ -21,52 +22,52 @@ class AttendancePendingViolationService ?string $semesterParam = null ): array { $schoolYear = filled($schoolYearParam) ? (string) $schoolYearParam : (string) $defaultSchoolYear; - $semester = filled($semesterParam) ? (string) $semesterParam : null; + $semester = filled($semesterParam) ? (string) $semesterParam : null; $debugInfo = [ 'school_year_param' => $schoolYear, - 'semester_param' => $semester, - 'class_students' => 0, - 'student_ids' => 0, - 'attendance_rows' => 0, - 'filtered_rows' => 0, - 'violations' => 0, - 'active_weeks' => 0, - 'abs_last5' => 0, - 'late_last5' => 0, + 'semester_param' => $semester, + 'class_students' => 0, + 'student_ids' => 0, + 'attendance_rows' => 0, + 'filtered_rows' => 0, + 'violations' => 0, + 'active_weeks' => 0, + 'abs_last5' => 0, + 'late_last5' => 0, ]; $resolved = $this->studentResolverService->resolveForSchoolYear($schoolYear, $semester); - $schoolYear = (string) ($resolved['school_year'] ?? $schoolYear); - $semester = $resolved['semester'] ?? $semester; - $studentIds = $resolved['student_ids'] ?? []; - $studentCodes = $resolved['student_codes'] ?? []; - $students = $resolved['students'] ?? []; + $schoolYear = (string) ($resolved['school_year'] ?? $schoolYear); + $semester = $resolved['semester'] ?? $semester; + $studentIds = $resolved['student_ids'] ?? []; + $studentCodes = $resolved['student_codes'] ?? []; + $students = $resolved['students'] ?? []; $studentCodeToId = $resolved['student_code_to_id'] ?? []; - $existingIds = $resolved['existing_ids'] ?? []; - $resolverDebug = $resolved['debug'] ?? []; + $existingIds = $resolved['existing_ids'] ?? []; + $resolverDebug = $resolved['debug'] ?? []; $debugInfo['class_students'] = $resolverDebug['class_students'] ?? 0; - $debugInfo['student_ids'] = $resolverDebug['student_ids'] ?? 0; + $debugInfo['student_ids'] = $resolverDebug['student_ids'] ?? 0; if (empty($studentIds) && empty($studentCodes)) { return [ - 'students' => [], + 'students' => [], 'school_year' => $schoolYear, - 'semester' => $semester, - 'error' => 'No student identifiers found for the current school year.', - 'debug' => $debugInfo, + 'semester' => $semester, + 'error' => 'No student identifiers found for the current school year.', + 'debug' => $debugInfo, ]; } if (empty($students)) { return [ - 'students' => [], + 'students' => [], 'school_year' => $schoolYear, - 'semester' => $semester, - 'error' => 'No students found matching attendance records.', - 'debug' => $debugInfo, + 'semester' => $semester, + 'error' => 'No students found matching attendance records.', + 'debug' => $debugInfo, ]; } @@ -90,14 +91,14 @@ class AttendancePendingViolationService 'is_reported', 'is_notified', ]) - ->when(! empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear)) - ->when(! empty($semester), fn ($q) => $q->where('semester', $semester)) + ->when(!empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear)) + ->when(!empty($semester), fn ($q) => $q->where('semester', $semester)) ->where(function ($q) use ($studentIds, $studentCodes) { - if (! empty($studentIds)) { + if (!empty($studentIds)) { $q->whereIn('student_id', $studentIds); } - if (! empty($studentCodes)) { - if (! empty($studentIds)) { + if (!empty($studentCodes)) { + if (!empty($studentIds)) { $q->orWhereIn('student_id', $studentCodes); } else { $q->whereIn('student_id', $studentCodes); @@ -117,16 +118,16 @@ class AttendancePendingViolationService if (empty($termRows)) { $latestAttendanceTerm = DB::table($this->attendanceDataModel->getTable()) ->select('school_year', 'semester', 'date') - ->when(! empty($studentIds), fn ($q) => $q->whereIn('student_id', $studentIds)) + ->when(!empty($studentIds), fn ($q) => $q->whereIn('student_id', $studentIds)) ->orderByDesc('date') ->first(); if ($latestAttendanceTerm) { - $schoolYear = ! empty($latestAttendanceTerm->school_year) + $schoolYear = !empty($latestAttendanceTerm->school_year) ? (string) $latestAttendanceTerm->school_year : $schoolYear; - $semester = ! empty($latestAttendanceTerm->semester) + $semester = !empty($latestAttendanceTerm->semester) ? (string) $latestAttendanceTerm->semester : $semester; @@ -149,14 +150,14 @@ class AttendancePendingViolationService 'is_reported', 'is_notified', ]) - ->when(! empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear)) - ->when(! empty($semester), fn ($q) => $q->where('semester', $semester)) + ->when(!empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear)) + ->when(!empty($semester), fn ($q) => $q->where('semester', $semester)) ->where(function ($q) use ($studentIds, $studentCodes) { - if (! empty($studentIds)) { + if (!empty($studentIds)) { $q->whereIn('student_id', $studentIds); } - if (! empty($studentCodes)) { - if (! empty($studentIds)) { + if (!empty($studentCodes)) { + if (!empty($studentIds)) { $q->orWhereIn('student_id', $studentCodes); } else { $q->whereIn('student_id', $studentCodes); @@ -176,10 +177,10 @@ class AttendancePendingViolationService if (empty($termRows)) { return [ - 'students' => [], + 'students' => [], 'school_year' => $schoolYear, - 'semester' => $semester, - 'debug' => $debugInfo, + 'semester' => $semester, + 'debug' => $debugInfo, ]; } } @@ -187,7 +188,7 @@ class AttendancePendingViolationService $attendanceRows = []; foreach ($termRows as $row) { $dStr = $row['date'] ?? null; - if (! $dStr) { + if (!$dStr) { continue; } @@ -197,7 +198,7 @@ class AttendancePendingViolationService continue; } - if ($d->lt($start) || ! $d->lt($endEx)) { + if ($d->lt($start) || !$d->lt($endEx)) { continue; } @@ -221,15 +222,15 @@ class AttendancePendingViolationService if (empty($attendanceRows)) { return [ - 'students' => [], + 'students' => [], 'school_year' => $schoolYear, - 'semester' => $semester, - 'debug' => $debugInfo, + 'semester' => $semester, + 'debug' => $debugInfo, ]; } $debugInfo['attendance_rows'] = count($termRows); - $debugInfo['filtered_rows'] = count($attendanceRows); + $debugInfo['filtered_rows'] = count($attendanceRows); $violations = $this->violationRuleEngine->computeViolations( $students, @@ -240,17 +241,17 @@ class AttendancePendingViolationService ); $ruleDebug = $this->violationRuleEngine->getDebugCompute(); - $debugInfo['violations'] = count($violations); + $debugInfo['violations'] = count($violations); $debugInfo['active_weeks'] = $ruleDebug['active_weeks'] ?? 0; - $debugInfo['by_student'] = $ruleDebug['by_student'] ?? 0; - $debugInfo['abs_last5'] = $ruleDebug['abs_last5'] ?? 0; - $debugInfo['late_last5'] = $ruleDebug['late_last5'] ?? 0; + $debugInfo['by_student'] = $ruleDebug['by_student'] ?? 0; + $debugInfo['abs_last5'] = $ruleDebug['abs_last5'] ?? 0; + $debugInfo['late_last5'] = $ruleDebug['late_last5'] ?? 0; return [ - 'students' => $violations, + 'students' => $violations, 'school_year' => $schoolYear, - 'semester' => $semester, - 'debug' => $debugInfo, + 'semester' => $semester, + 'debug' => $debugInfo, ]; } -} +} \ No newline at end of file diff --git a/app/Services/AttendanceTracking/AttendanceTrackingService.php b/app/Services/AttendanceTracking/AttendanceTrackingService.php index bb976248..2414a8fc 100644 --- a/app/Services/AttendanceTracking/AttendanceTrackingService.php +++ b/app/Services/AttendanceTracking/AttendanceTrackingService.php @@ -2,13 +2,11 @@ namespace App\Services\AttendanceTracking; -use App\Http\Controllers\Api\AttendanceTracking\AttendanceTrackingController; use App\Models\Configuration; -use Carbon\Carbon; use Illuminate\Support\Facades\Validator; /** - * Facade used by {@see AttendanceTrackingController}. + * Facade used by {@see \App\Http\Controllers\Api\AttendanceTracking\AttendanceTrackingController}. */ class AttendanceTrackingService { @@ -17,7 +15,8 @@ class AttendanceTrackingService protected AttendanceCaseQueryService $caseQueryService, protected AttendanceNotificationWorkflowService $workflowService, protected AttendanceCommunicationSupportService $communicationSupportService, - ) {} + ) { + } protected function defaultSchoolYear(): string { @@ -153,7 +152,7 @@ class AttendanceTrackingService $ymd = null; if (! empty($data['date'])) { try { - $ymd = Carbon::parse((string) $data['date'])->format('Y-m-d'); + $ymd = \Carbon\Carbon::parse((string) $data['date'])->format('Y-m-d'); } catch (\Throwable) { $ymd = null; } diff --git a/app/Services/AttendanceTracking/AttendanceViolationStudentResolverService.php b/app/Services/AttendanceTracking/AttendanceViolationStudentResolverService.php index 28e7531a..e54bc98c 100644 --- a/app/Services/AttendanceTracking/AttendanceViolationStudentResolverService.php +++ b/app/Services/AttendanceTracking/AttendanceViolationStudentResolverService.php @@ -13,13 +13,14 @@ class AttendanceViolationStudentResolverService protected Student $studentModel, protected StudentClass $studentClassModel, protected AttendanceData $attendanceDataModel - ) {} + ) { + } public function resolveForSchoolYear(string $schoolYear, ?string $semester = null): array { $debug = [ 'class_students' => 0, - 'student_ids' => 0, + 'student_ids' => 0, ]; $classStudentsQuery = $this->studentClassModel->query(); @@ -40,9 +41,9 @@ class AttendanceViolationStudentResolverService ->orderByDesc('id') ->first(); - if ($latestTerm && ! empty($latestTerm->school_year)) { + if ($latestTerm && !empty($latestTerm->school_year)) { $schoolYear = (string) $latestTerm->school_year; - if (! empty($latestTerm->semester)) { + if (!empty($latestTerm->semester)) { $semester = (string) $latestTerm->semester; } @@ -72,14 +73,14 @@ class AttendanceViolationStudentResolverService if (empty($studentIds) && empty($studentCodes)) { return [ - 'school_year' => $schoolYear, - 'semester' => $semester, - 'student_ids' => [], - 'student_codes' => [], - 'students' => [], - 'student_code_to_id' => [], - 'existing_ids' => [], - 'debug' => $debug, + 'school_year' => $schoolYear, + 'semester' => $semester, + 'student_ids' => [], + 'student_codes' => [], + 'students' => [], + 'student_code_to_id'=> [], + 'existing_ids' => [], + 'debug' => $debug, ]; } @@ -90,14 +91,14 @@ class AttendanceViolationStudentResolverService [$studentCodeToId, $existingIds] = $this->buildLookupMaps($students); return [ - 'school_year' => $schoolYear, - 'semester' => $semester, - 'student_ids' => $studentIds, - 'student_codes' => $studentCodes, - 'students' => $students, + 'school_year' => $schoolYear, + 'semester' => $semester, + 'student_ids' => $studentIds, + 'student_codes' => $studentCodes, + 'students' => $students, 'student_code_to_id' => $studentCodeToId, - 'existing_ids' => $existingIds, - 'debug' => $debug, + 'existing_ids' => $existingIds, + 'debug' => $debug, ]; } @@ -113,12 +114,12 @@ class AttendanceViolationStudentResolverService return null; } - if (! isset($existingIds[$sid])) { + if (!isset($existingIds[$sid])) { $students[] = [ - 'id' => $sid, + 'id' => $sid, 'school_id' => (string) $sid, 'firstname' => (string) $sid, - 'lastname' => '', + 'lastname' => '', 'parent_id' => 0, ]; $existingIds[$sid] = true; @@ -138,12 +139,12 @@ class AttendanceViolationStudentResolverService $sid = abs(crc32($code)) ?: random_int(3000000, 3999999); $studentCodeToId[$code] = $sid; - if (! isset($existingIds[$sid])) { + if (!isset($existingIds[$sid])) { $students[] = [ - 'id' => $sid, + 'id' => $sid, 'school_id' => $code, 'firstname' => $code, - 'lastname' => '', + 'lastname' => '', 'parent_id' => 0, ]; $existingIds[$sid] = true; @@ -184,7 +185,7 @@ class AttendanceViolationStudentResolverService $attendanceStudents = DB::table($this->attendanceDataModel->getTable()) ->selectRaw('DISTINCT student_id') - ->when(! empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear)) + ->when(!empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear)) ->orderBy('student_id') ->get(); @@ -206,7 +207,7 @@ class AttendanceViolationStudentResolverService protected function filterInactiveIdentifiers(array $studentIds, array $studentCodes): array { - if (! empty($studentIds)) { + if (!empty($studentIds)) { $inactiveRows = $this->studentModel->query() ->select('id') ->whereIn('id', $studentIds) @@ -221,11 +222,11 @@ class AttendanceViolationStudentResolverService $studentIds = array_values(array_filter( $studentIds, - static fn ($id) => ! isset($inactiveIdSet[$id]) + static fn ($id) => !isset($inactiveIdSet[$id]) )); } - if (! empty($studentCodes)) { + if (!empty($studentCodes)) { $inactiveCodeRows = $this->studentModel->query() ->select('school_id') ->whereIn('school_id', $studentCodes) @@ -240,7 +241,7 @@ class AttendanceViolationStudentResolverService $studentCodes = array_values(array_filter( $studentCodes, - static fn ($code) => $code !== '' && ! isset($inactiveCodeSet[$code]) + static fn ($code) => $code !== '' && !isset($inactiveCodeSet[$code]) )); } @@ -251,7 +252,7 @@ class AttendanceViolationStudentResolverService { $students = []; - if (! empty($studentIds)) { + if (!empty($studentIds)) { $students = $this->studentModel->query() ->whereIn('id', $studentIds) ->where('is_active', 1) @@ -259,7 +260,7 @@ class AttendanceViolationStudentResolverService ->toArray(); } - if (! empty($studentCodes)) { + if (!empty($studentCodes)) { $byCode = $this->studentModel->query() ->whereIn('school_id', $studentCodes) ->where('is_active', 1) @@ -270,7 +271,7 @@ class AttendanceViolationStudentResolverService foreach ($byCode as $s) { $sid = (int) ($s['id'] ?? 0); - if ($sid > 0 && ! isset($seen[$sid])) { + if ($sid > 0 && !isset($seen[$sid])) { $students[] = $s; $seen[$sid] = true; } @@ -292,14 +293,14 @@ class AttendanceViolationStudentResolverService } foreach ($studentCodes as $code) { - if (! isset($knownCodes[$code])) { + if (!isset($knownCodes[$code])) { $virtualId = abs(crc32($code)) ?: random_int(1000000, 1999999); $students[] = [ - 'id' => $virtualId, - 'school_id' => $code, - 'firstname' => $code, - 'lastname' => '', - 'parent_id' => 0, + 'id' => $virtualId, + 'school_id' => $code, + 'firstname' => $code, + 'lastname' => '', + 'parent_id' => 0, 'class_name' => '', ]; } @@ -316,13 +317,13 @@ class AttendanceViolationStudentResolverService if (is_numeric($sidOrCode)) { $sid = (int) $sidOrCode; - if ($sid > 0 && ! isset($existingIds[$sid])) { + if ($sid > 0 && !isset($existingIds[$sid])) { $students[] = [ - 'id' => $sid, - 'school_id' => (string) $sid, - 'firstname' => (string) $sid, - 'lastname' => '', - 'parent_id' => 0, + 'id' => $sid, + 'school_id' => (string) $sid, + 'firstname' => (string) $sid, + 'lastname' => '', + 'parent_id' => 0, 'class_name' => '', ]; $existingIds[$sid] = true; @@ -330,14 +331,14 @@ class AttendanceViolationStudentResolverService } else { $code = (string) $sidOrCode; - if ($code !== '' && ! isset($studentCodeToId[$code])) { + if ($code !== '' && !isset($studentCodeToId[$code])) { $virtualId = abs(crc32($code)) ?: random_int(2000000, 2999999); $students[] = [ - 'id' => $virtualId, - 'school_id' => $code, - 'firstname' => $code, - 'lastname' => '', - 'parent_id' => 0, + 'id' => $virtualId, + 'school_id' => $code, + 'firstname' => $code, + 'lastname' => '', + 'parent_id' => 0, 'class_name' => '', ]; diff --git a/app/Services/AttendanceTracking/DefaultAttendanceMailerService.php b/app/Services/AttendanceTracking/DefaultAttendanceMailerService.php index e39aa0a4..0cb9946a 100644 --- a/app/Services/AttendanceTracking/DefaultAttendanceMailerService.php +++ b/app/Services/AttendanceTracking/DefaultAttendanceMailerService.php @@ -10,7 +10,8 @@ class DefaultAttendanceMailerService implements AttendanceMailerService public function __construct( protected EmailService $emailService, protected AttendanceEmailComposerService $emailComposerService - ) {} + ) { + } public function send(string $to, string $subject, string $html): bool { @@ -25,24 +26,24 @@ class DefaultAttendanceMailerService implements AttendanceMailerService } $student = (array) ($payload['student'] ?? []); - $studentName = trim((string) ($student['firstname'] ?? '').' '.(string) ($student['lastname'] ?? '')); + $studentName = trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? '')); $subjectType = (string) ($payload['subject'] ?? 'Attendance'); $date = substr((string) ($payload['date'] ?? now()->toDateString()), 0, 10); $subject = "Attendance Notice: {$subjectType}"; - $body = '

Dear '.e((string) data_get($payload, 'parent.name', 'Parent/Guardian')).',

' - .'

This is an attendance notification for your student.

' - .'
    ' - .'
  • Student: '.e($studentName !== '' ? $studentName : 'Student').'
  • ' - .'
  • Date: '.e($date).'
  • ' - .'
  • Attendance: '.e($subjectType).'
  • ' - .'
' - .'

If you have any questions, please contact the school office.

'; + $body = '

Dear ' . e((string) data_get($payload, 'parent.name', 'Parent/Guardian')) . ',

' + . '

This is an attendance notification for your student.

' + . '
    ' + . '
  • Student: ' . e($studentName !== '' ? $studentName : 'Student') . '
  • ' + . '
  • Date: ' . e($date) . '
  • ' + . '
  • Attendance: ' . e($subjectType) . '
  • ' + . '
' + . '

If you have any questions, please contact the school office.

'; $html = $this->emailComposerService->renderWithEmailLayout($subject, $body); - if (! $this->send($to, $subject, $html)) { - Log::error('Attendance notification email failed for '.$to); + if (!$this->send($to, $subject, $html)) { + Log::error('Attendance notification email failed for ' . $to); throw new \RuntimeException('Failed to send attendance notification email.'); } } diff --git a/app/Services/AttendanceTracking/ViolationRuleEngineService.php b/app/Services/AttendanceTracking/ViolationRuleEngineService.php index 6524a29d..53cad6df 100644 --- a/app/Services/AttendanceTracking/ViolationRuleEngineService.php +++ b/app/Services/AttendanceTracking/ViolationRuleEngineService.php @@ -13,13 +13,13 @@ use Throwable; class ViolationRuleEngineService { protected array $debugCompute = []; - protected ?array $attendanceReportedColumns = null; public function __construct( protected AttendanceTracking $attendanceTrackingModel, protected AttendanceParentLookupService $parentLookupService - ) {} + ) { + } public function getDebugCompute(): array { @@ -54,10 +54,10 @@ class ViolationRuleEngineService continue; } - $ymd = substr((string) ($r['date'] ?? ''), 0, 10); + $ymd = substr((string) ($r['date'] ?? ''), 0, 10); $stat = strtolower(trim((string) ($r['status'] ?? ''))); - if (! in_array($stat, ['absent', 'late'], true)) { + if (!in_array($stat, ['absent', 'late'], true)) { continue; } @@ -69,10 +69,10 @@ class ViolationRuleEngineService [$syStart, $syEnd] = $this->deriveSchoolYearBounds($schoolYear); $weekRowsSource = null; - if (! empty($weekRowsFallback)) { + if (!empty($weekRowsFallback)) { foreach ($weekRowsFallback as $r) { $st = strtolower(trim((string) ($r['status'] ?? ''))); - if ($st !== '' && ! in_array($st, ['absent', 'late'], true)) { + if ($st !== '' && !in_array($st, ['absent', 'late'], true)) { $weekRowsSource = $weekRowsFallback; break; } @@ -86,9 +86,9 @@ class ViolationRuleEngineService return []; } - $weekIndex = array_flip($activeWeekKeys); - $currentWeekIdx = count($activeWeekKeys) - 1; - $windowStartIdx = max(0, $currentWeekIdx - 4); + $weekIndex = array_flip($activeWeekKeys); + $currentWeekIdx = count($activeWeekKeys) - 1; + $windowStartIdx = max(0, $currentWeekIdx - 4); $requiredWeeksCount = $currentWeekIdx - $windowStartIdx + 1; $keepLastWeeks = function (array $dates) use ($weekIndex, $windowStartIdx, $currentWeekIdx): array { @@ -105,18 +105,17 @@ class ViolationRuleEngineService } $out = array_values(array_unique($out)); rsort($out); - return $out; }; $classByStudent = []; try { $studentIdsForClass = array_values(array_unique(array_map( - static fn ($s) => (int) ($s['id'] ?? 0), + static fn($s) => (int) ($s['id'] ?? 0), $students ))); - if (! empty($studentIdsForClass)) { + if (!empty($studentIdsForClass)) { $rows = DB::table('student_class as sc') ->select([ 'sc.student_id', @@ -138,18 +137,18 @@ class ViolationRuleEngineService continue; } - if (! isset($classByStudent[$sid])) { + if (!isset($classByStudent[$sid])) { $classByStudent[$sid] = [ - 'class_section_id' => $row->class_section_id ?? null, + 'class_section_id' => $row->class_section_id ?? null, 'class_section_name' => (string) ($row->class_section_name ?? ''), - 'class_id' => $row->class_id ?? null, - 'class_name' => (string) ($row->class_name ?? ''), + 'class_id' => $row->class_id ?? null, + 'class_name' => (string) ($row->class_name ?? ''), ]; } } } } catch (Throwable $e) { - Log::debug('computeViolations(): class prefetch failed: '.$e->getMessage()); + Log::debug('computeViolations(): class prefetch failed: ' . $e->getMessage()); } $out = []; @@ -157,26 +156,26 @@ class ViolationRuleEngineService $lateCountLast5 = 0; foreach ($students as $stu) { - $sid = (int) ($stu['id'] ?? 0); - $name = trim(($stu['firstname'] ?? '').' '.($stu['lastname'] ?? '')); + $sid = (int) ($stu['id'] ?? 0); + $name = trim(($stu['firstname'] ?? '') . ' ' . ($stu['lastname'] ?? '')); - $absDatesAll = array_values(array_unique($byStudent[$sid]['absent'] ?? [])); + $absDatesAll = array_values(array_unique($byStudent[$sid]['absent'] ?? [])); $lateDatesAll = array_values(array_unique($byStudent[$sid]['late'] ?? [])); - $absDates = $keepLastWeeks($absDatesAll); + $absDates = $keepLastWeeks($absDatesAll); $lateDates = $keepLastWeeks($lateDatesAll); if (empty($absDates) && empty($lateDates)) { continue; } - $absWeekIdx = $this->datesToWeekIndices($absDates, $weekIndex); + $absWeekIdx = $this->datesToWeekIndices($absDates, $weekIndex); $lateWeekIdx = $this->datesToWeekIndices($lateDates, $weekIndex); - $absCountLast5 += count($absDates); + $absCountLast5 += count($absDates); $lateCountLast5 += count($lateDates); $absenceViolation = null; - if (! empty($absDates)) { + if (!empty($absDates)) { $lastAbsDate = $absDates[0]; $A2row = $this->hasNConsecutiveItems($absDates, 2, 7); @@ -189,47 +188,47 @@ class ViolationRuleEngineService if ($A4row || $A_in5w4) { $absenceViolation = [ - 'type' => 'absence', - 'code' => 'ABS_4', - 'severity' => 4, - 'action' => 'expel_notify', - 'color' => '#ff4d4f', - 'title' => '4 Absences (in a row or within last 5 active weeks)', + 'type' => 'absence', + 'code' => 'ABS_4', + 'severity' => 4, + 'action' => 'expel_notify', + 'color' => '#ff4d4f', + 'title' => '4 Absences (in a row or within last 5 active weeks)', 'description' => 'Notify team to inform parent about expulsion and send email.', - 'last_date' => $lastAbsDate, + 'last_date' => $lastAbsDate, ]; } elseif ($A3row || $A_in4w3) { $absenceViolation = [ - 'type' => 'absence', - 'code' => 'ABS_3', - 'severity' => 3, - 'action' => 'team_notify', - 'color' => '#fa8c16', - 'title' => '3 Absences (in a row or within last 4 active weeks)', + 'type' => 'absence', + 'code' => 'ABS_3', + 'severity' => 3, + 'action' => 'team_notify', + 'color' => '#fa8c16', + 'title' => '3 Absences (in a row or within last 4 active weeks)', 'description' => 'Team calls parent and sends email.', - 'last_date' => $lastAbsDate, + 'last_date' => $lastAbsDate, ]; } elseif ($A2row || $A_in3w2) { $absenceViolation = [ - 'type' => 'absence', - 'code' => 'ABS_2', - 'severity' => 2, - 'action' => 'team_notify', - 'color' => '#fadb14', - 'title' => '2 Absences (in a row or within last 3 active weeks)', + 'type' => 'absence', + 'code' => 'ABS_2', + 'severity' => 2, + 'action' => 'team_notify', + 'color' => '#fadb14', + 'title' => '2 Absences (in a row or within last 3 active weeks)', 'description' => 'Team calls parent and sends email.', - 'last_date' => $lastAbsDate, + 'last_date' => $lastAbsDate, ]; } } $lateViolation = null; - if (! empty($lateDates)) { + if (!empty($lateDates)) { $lastLateDate = $lateDates[0]; - $L2row = $this->hasNConsecutiveItems($lateDates, 2, 7); - $L3row = $this->hasNConsecutiveItems($lateDates, 3, 7); - $L4row = $this->hasNConsecutiveItems($lateDates, 4, 7); + $L2row = $this->hasNConsecutiveItems($lateDates, 2, 7); + $L3row = $this->hasNConsecutiveItems($lateDates, 3, 7); + $L4row = $this->hasNConsecutiveItems($lateDates, 4, 7); $L_in3w2 = $this->hasNInWActiveWeeks($lateWeekIdx, 2, 3); $L_in4w3 = $this->hasNInWActiveWeeks($lateWeekIdx, 3, 4); @@ -239,7 +238,7 @@ class ViolationRuleEngineService $lateWeeksSet = array_flip($lateWeekIdx); $lateCoversAllWindowWeeks = true; for ($i = $windowStartIdx; $i <= $currentWeekIdx; $i++) { - if (! isset($lateWeeksSet[$i])) { + if (!isset($lateWeeksSet[$i])) { $lateCoversAllWindowWeeks = false; break; } @@ -248,41 +247,41 @@ class ViolationRuleEngineService if ($L4row || $lateCoversAllWindowWeeks) { $lateViolation = [ - 'type' => 'late', - 'code' => 'LATE_4', - 'severity' => 4, - 'action' => 'team_notify', - 'color' => '#ff4d4f', - 'title' => '4 Lates in a row OR in each of the last 4 active weeks', + 'type' => 'late', + 'code' => 'LATE_4', + 'severity' => 4, + 'action' => 'team_notify', + 'color' => '#ff4d4f', + 'title' => '4 Lates in a row OR in each of the last 4 active weeks', 'description' => 'Team calls parent and sends email.', - 'last_date' => $lastLateDate, + 'last_date' => $lastLateDate, ]; } else { $twoLatesOneAbsWithin4 = $this->twoLatesOneAbsInWWeeks($lateWeekIdx, $absWeekIdx, 4); if ($L3row || $L_in4w3 || $twoLatesOneAbsWithin4) { $lateViolation = [ - 'type' => $twoLatesOneAbsWithin4 ? 'mix' : 'late', - 'code' => $twoLatesOneAbsWithin4 ? 'MIX_L2A1' : 'LATE_3', - 'severity' => 3, - 'action' => 'team_notify', - 'color' => '#002766', - 'title' => $twoLatesOneAbsWithin4 + 'type' => $twoLatesOneAbsWithin4 ? 'mix' : 'late', + 'code' => $twoLatesOneAbsWithin4 ? 'MIX_L2A1' : 'LATE_3', + 'severity' => 3, + 'action' => 'team_notify', + 'color' => '#002766', + 'title' => $twoLatesOneAbsWithin4 ? '2 Lates + 1 Absence (within last 4 active weeks)' : '3 Lates (in a row or within last 4 active weeks)', 'description' => 'Team calls parent and sends email.', - 'last_date' => $lastLateDate, + 'last_date' => $lastLateDate, ]; } elseif ($L2row || $L_in3w2) { $lateViolation = [ - 'type' => 'late', - 'code' => 'LATE_2', - 'severity' => 1, - 'action' => 'auto_email', - 'color' => '#bae7ff', - 'title' => '2 Lates (in a row or within last 3 active weeks)', + 'type' => 'late', + 'code' => 'LATE_2', + 'severity' => 1, + 'action' => 'auto_email', + 'color' => '#bae7ff', + 'title' => '2 Lates (in a row or within last 3 active weeks)', 'description' => 'Send automated email to parent.', - 'last_date' => $lastLateDate, + 'last_date' => $lastLateDate, ]; } } @@ -290,20 +289,20 @@ class ViolationRuleEngineService $chosen = $this->chooseHigherSeverity($absenceViolation, $lateViolation); - if (! $chosen && count($absDates) === 1) { + if (!$chosen && count($absDates) === 1) { $chosen = [ - 'type' => 'absence', - 'code' => 'ABS_1', - 'severity' => 1, - 'action' => 'auto_email', - 'color' => '#e6f7ff', - 'title' => '1 Unreported Absence', + 'type' => 'absence', + 'code' => 'ABS_1', + 'severity' => 1, + 'action' => 'auto_email', + 'color' => '#e6f7ff', + 'title' => '1 Unreported Absence', 'description' => 'Send automated email to parent.', - 'last_date' => $absDates[0], + 'last_date' => $absDates[0], ]; } - if (! $chosen) { + if (!$chosen) { continue; } @@ -316,51 +315,51 @@ class ViolationRuleEngineService ->where('school_year', $schoolYear) ->where('date', '>=', $start) ->where('date', '<', $end) - ->where('reason', 'like', '%'.$chosen['code'].'%'); + ->where('reason', 'like', '%' . $chosen['code'] . '%'); if ($semester !== null) { $trackingQ->where('semester', $semester); } - $tracking = $trackingQ->orderByDesc('date')->first(); - $tracking = $tracking?->toArray() ?? []; + $tracking = $trackingQ->orderByDesc('date')->first(); + $tracking = $tracking?->toArray() ?? []; $isNotified = (bool) ($tracking['is_notified'] ?? 0); - $notifCnt = (int) ($tracking['notif_counter'] ?? 0); + $notifCnt = (int) ($tracking['notif_counter'] ?? 0); $cls = $classByStudent[$sid] ?? []; $classLabel = (string) ($cls['class_section_name'] ?? ''); - if ($classLabel === '' && ! empty($cls['class_name'])) { + if ($classLabel === '' && !empty($cls['class_name'])) { $classLabel = (string) $cls['class_name']; } $out[] = [ - 'id' => $sid, - 'name' => $name, - 'class_name' => $classLabel, + 'id' => $sid, + 'name' => $name, + 'class_name' => $classLabel, 'class_section_name' => (string) ($cls['class_section_name'] ?? ''), - 'className' => (string) ($cls['class_name'] ?? ''), - 'class_id' => $cls['class_id'] ?? null, + 'className' => (string) ($cls['class_name'] ?? ''), + 'class_id' => $cls['class_id'] ?? null, 'class_section_id' => $cls['class_section_id'] ?? null, - 'parent_email' => $parent['email'] ?? '', - 'parent_name' => $parent['parent_name'] ?? '', - 'parent_phone' => $parent['phone'] ?? null, - 'violation' => $chosen['title'], - 'violation_code' => $chosen['code'], - 'type' => $chosen['type'], - 'severity' => $chosen['severity'], - 'action' => $chosen['action'], - 'color' => $chosen['color'], - 'last_absence' => $absDates[0] ?? null, - 'last_late' => $lateDates[0] ?? null, - 'last_date' => $chosen['last_date'], - 'is_notified' => $isNotified, - 'notif_counter' => $notifCnt, - 'absences' => $absDates, - 'lates' => $lateDates, + 'parent_email' => $parent['email'] ?? '', + 'parent_name' => $parent['parent_name'] ?? '', + 'parent_phone' => $parent['phone'] ?? null, + 'violation' => $chosen['title'], + 'violation_code' => $chosen['code'], + 'type' => $chosen['type'], + 'severity' => $chosen['severity'], + 'action' => $chosen['action'], + 'color' => $chosen['color'], + 'last_absence' => $absDates[0] ?? null, + 'last_late' => $lateDates[0] ?? null, + 'last_date' => $chosen['last_date'], + 'is_notified' => $isNotified, + 'notif_counter' => $notifCnt, + 'absences' => $absDates, + 'lates' => $lateDates, ]; } - $this->debugCompute['abs_last5'] = $absCountLast5; + $this->debugCompute['abs_last5'] = $absCountLast5; $this->debugCompute['late_last5'] = $lateCountLast5; return $out; @@ -371,10 +370,8 @@ class ViolationRuleEngineService if ($a && $b) { if ($a['severity'] === $b['severity']) { $prio = ['expel_notify' => 3, 'team_notify' => 2, 'auto_email' => 1]; - return ($prio[$a['action']] ?? 0) >= ($prio[$b['action']] ?? 0) ? $a : $b; } - return $a['severity'] > $b['severity'] ? $a : $b; } @@ -389,7 +386,7 @@ class ViolationRuleEngineService $this->attendanceReportedColumns = [ 'is_reported' => Schema::hasColumn($table, 'is_reported'), - 'reported' => Schema::hasColumn($table, 'reported'), + 'reported' => Schema::hasColumn($table, 'reported'), ]; return $this->attendanceReportedColumns; @@ -399,15 +396,15 @@ class ViolationRuleEngineService { $cols = $this->attendanceReportedColumns($table); - if (! empty($cols['is_reported'])) { + if (!empty($cols['is_reported'])) { $qb->whereRaw("(LOWER(TRIM(COALESCE(is_reported, ''))) NOT IN ('yes','1','true','y','on'))"); } - if (! empty($cols['reported'])) { + if (!empty($cols['reported'])) { $qb->whereRaw("(LOWER(TRIM(COALESCE(reported, ''))) NOT IN ('yes','1','true','y','on'))"); } $qb->whereRaw("(LOWER(COALESCE(reason, '')) NOT LIKE '%parent-reported%')") - ->whereRaw("(LOWER(COALESCE(reason, '')) NOT LIKE '%parent reported%')"); + ->whereRaw("(LOWER(COALESCE(reason, '')) NOT LIKE '%parent reported%')"); if (Schema::hasTable('parent_attendance_reports')) { $qb->whereRaw("NOT EXISTS ( @@ -421,16 +418,14 @@ class ViolationRuleEngineService public function deriveSchoolYearBounds(string $schoolYear): array { - if (! preg_match('/^(\d{4})-(\d{4})$/', $schoolYear, $m)) { - $y = (int) date('Y'); + if (!preg_match('/^(\d{4})-(\d{4})$/', $schoolYear, $m)) { + $y = (int) date('Y'); $startY = (int) (date('n') >= 8 ? $y : $y - 1); - return [sprintf('%d-08-01', $startY), sprintf('%d-07-31', $startY + 1)]; } $startY = (int) $m[1]; - $endY = (int) $m[2]; - + $endY = (int) $m[2]; return [sprintf('%d-08-01', $startY), sprintf('%d-07-31', $endY)]; } @@ -451,10 +446,9 @@ class ViolationRuleEngineService public function dayBounds(string $ymd): array { $d = substr($ymd, 0, 10); - return [ - $d.' 00:00:00', - date('Y-m-d', strtotime($d.' +1 day')).' 00:00:00', + $d . ' 00:00:00', + date('Y-m-d', strtotime($d . ' +1 day')) . ' 00:00:00', ]; } @@ -467,10 +461,10 @@ class ViolationRuleEngineService ): array { $weeks = []; - if (! empty($weekRowsFallback)) { + if (!empty($weekRowsFallback)) { foreach ($weekRowsFallback as $r) { $d = $r['date'] ?? null; - if (! $d) { + if (!$d) { continue; } $ts = strtotime($d); @@ -496,10 +490,10 @@ class ViolationRuleEngineService $q->whereNull('reason') ->orWhere(function ($q2) { $q2->where('reason', 'not like', '%break%') - ->where('reason', 'not like', '%cancel%'); + ->where('reason', 'not like', '%cancel%'); }); }) - ->when($semester !== null && $semester !== '', fn ($q) => $q->where('semester', $semester)) + ->when($semester !== null && $semester !== '', fn($q) => $q->where('semester', $semester)) ->groupBy(DB::raw('DATE(date)')) ->orderBy('ymd') ->get(); @@ -527,7 +521,6 @@ class ViolationRuleEngineService } $idx = array_keys($set); sort($idx); - return $idx; } @@ -549,16 +542,14 @@ class ViolationRuleEngineService if (Str::startsWith($code, 'ABS_4')) { return 5; } - return 5; } public function isoWeekStartYmd(string $weekKey): string { if (preg_match('/^(\d{4})-W(\d{2})$/', $weekKey, $m)) { - return date('Y-m-d', strtotime($m[1].'-W'.$m[2].'-1')); + return date('Y-m-d', strtotime($m[1] . '-W' . $m[2] . '-1')); } - return date('Y-m-d'); } @@ -580,15 +571,14 @@ class ViolationRuleEngineService if (empty($activeWeekKeys)) { $days = ($windowWeeks * 7) - 1; - - return date('Y-m-d', strtotime($endBound.' -'.$days.' days')); + return date('Y-m-d', strtotime($endBound . ' -' . $days . ' days')); } $activeWeekKeys = array_values($activeWeekKeys); $weekIndex = array_flip($activeWeekKeys); $endWeekKey = date('o-\WW', strtotime($endBound)); - if (! isset($weekIndex[$endWeekKey])) { + if (!isset($weekIndex[$endWeekKey])) { $endWeekKey = null; for ($i = count($activeWeekKeys) - 1; $i >= 0; $i--) { $wkStart = $this->isoWeekStartYmd($activeWeekKeys[$i]); @@ -672,12 +662,11 @@ class ViolationRuleEngineService while ($iL2 < count($L)) { $windowStart = $L[$iL1]; - $windowEnd = $windowStart + ($w - 1); + $windowEnd = $windowStart + ($w - 1); if ($L[$iL2] > $windowEnd) { $iL1++; $iL2 = $iL1 + 1; - continue; } @@ -698,4 +687,4 @@ class ViolationRuleEngineService return false; } -} +} \ No newline at end of file diff --git a/app/Services/Auth/ApiLoginSecurityService.php b/app/Services/Auth/ApiLoginSecurityService.php index dd9abebd..1c3b18b5 100644 --- a/app/Services/Auth/ApiLoginSecurityService.php +++ b/app/Services/Auth/ApiLoginSecurityService.php @@ -2,9 +2,9 @@ namespace App\Services\Auth; -use App\Models\Configuration; use App\Models\IpAttempt; use App\Models\LoginActivity; +use App\Models\Configuration; use App\Models\User; use Carbon\CarbonImmutable; use Illuminate\Http\Request; @@ -22,7 +22,7 @@ class ApiLoginSecurityService public function isIpBlocked(string $ip): bool { $row = IpAttempt::query()->where('ip_address', $ip)->first(); - if (! $row || ! $row->blocked_until) { + if (!$row || !$row->blocked_until) { return false; } diff --git a/app/Services/Auth/AuthSessionService.php b/app/Services/Auth/AuthSessionService.php index bc7f044f..04cda57d 100644 --- a/app/Services/Auth/AuthSessionService.php +++ b/app/Services/Auth/AuthSessionService.php @@ -3,11 +3,12 @@ namespace App\Services\Auth; use App\Models\Configuration; +use App\Services\ApplicationUrlService; use App\Models\LoginActivity; use App\Models\Preferences; use App\Models\Role; use App\Models\User; -use App\Services\ApplicationUrlService; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Log; @@ -20,7 +21,8 @@ class AuthSessionService public function __construct( private ApplicationUrlService $urls, - ) {} + ) { + } /** * Sanitizes login redirects to same-host relative paths only. diff --git a/app/Services/Auth/PermissionCheckService.php b/app/Services/Auth/PermissionCheckService.php index e570c625..767e52ac 100644 --- a/app/Services/Auth/PermissionCheckService.php +++ b/app/Services/Auth/PermissionCheckService.php @@ -12,7 +12,7 @@ class PermissionCheckService ->where('name', $permissionName) ->value('id'); - if (! $permissionId) { + if (!$permissionId) { return false; } diff --git a/app/Services/Auth/RegistrationCaptchaService.php b/app/Services/Auth/RegistrationCaptchaService.php index f33cbf2d..90cfc3fd 100644 --- a/app/Services/Auth/RegistrationCaptchaService.php +++ b/app/Services/Auth/RegistrationCaptchaService.php @@ -9,8 +9,7 @@ class RegistrationCaptchaService $ip = (string) (request()?->ip() ?? 'unknown'); $ua = (string) (request()?->header('User-Agent') ?? ''); $hash = substr(sha1($ua), 0, 12); - - return 'captcha:'.$ip.':'.$hash; + return 'captcha:' . $ip . ':' . $hash; } public function generate(?int $length = null): string diff --git a/app/Services/Auth/RegistrationFormatterService.php b/app/Services/Auth/RegistrationFormatterService.php index 1d6e1b48..3d00572e 100644 --- a/app/Services/Auth/RegistrationFormatterService.php +++ b/app/Services/Auth/RegistrationFormatterService.php @@ -6,7 +6,9 @@ use App\Services\PhoneFormatterService; class RegistrationFormatterService { - public function __construct(private PhoneFormatterService $phoneFormatter) {} + public function __construct(private PhoneFormatterService $phoneFormatter) + { + } public function format(array $payload): array { @@ -28,7 +30,7 @@ class RegistrationFormatterService 'accept_school_policy' => (int) ($payload['accept_school_policy'] ?? 0), ]; - $noSecondInfo = ! empty($payload['no_second_parent_info']); + $noSecondInfo = !empty($payload['no_second_parent_info']); $secondFirstname = $this->formatName($g('second_firstname')); $secondLastname = $this->formatName($g('second_lastname')); @@ -36,7 +38,7 @@ class RegistrationFormatterService $secondEmail = $this->formatEmail($g('second_email')); $secondCellphone = $this->phoneFormatter->formatPhoneNumber($g('second_cellphone')); - $secondProvided = ! $noSecondInfo && ( + $secondProvided = !$noSecondInfo && ( $secondFirstname !== '' || $secondLastname !== '' || $secondGender !== '' || @@ -62,7 +64,7 @@ class RegistrationFormatterService return ''; } - return ucwords(strtolower($name), ' -'); + return ucwords(strtolower($name), " -"); } private function formatEmail(string $email): string diff --git a/app/Services/Auth/RegistrationService.php b/app/Services/Auth/RegistrationService.php index 5192562b..94eb036c 100644 --- a/app/Services/Auth/RegistrationService.php +++ b/app/Services/Auth/RegistrationService.php @@ -20,12 +20,13 @@ class RegistrationService private RegistrationFormatterService $formatter, private RegistrationCaptchaService $captchaService, private ApplicationUrlService $urls, - ) {} + ) { + } public function register(array $payload): array { $captcha = (string) ($payload['captcha'] ?? ''); - if (! $this->captchaService->verify($captcha)) { + if (!$this->captchaService->verify($captcha)) { return [ 'ok' => false, 'code' => 'captcha_invalid', @@ -33,15 +34,15 @@ class RegistrationService ]; } - $isParent = ! empty($payload['is_parent']); - $noSecondInfo = ! empty($payload['no_second_parent_info']); + $isParent = !empty($payload['is_parent']); + $noSecondInfo = !empty($payload['no_second_parent_info']); $formatted = $this->formatter->format($payload); $email = (string) ($formatted['email'] ?? ''); $existing = User::query()->where('email', $email)->first(); if ($existing) { - $pending = ! empty($existing->token) && (int) ($existing->is_verified ?? 0) === 0; + $pending = !empty($existing->token) && (int) ($existing->is_verified ?? 0) === 0; if ($pending) { return [ 'ok' => false, @@ -59,7 +60,7 @@ class RegistrationService $roleName = $isParent ? 'parent' : 'guest'; $role = Role::query()->where('name', $roleName)->first(); - if (! $role) { + if (!$role) { return [ 'ok' => false, 'code' => 'role_missing', @@ -112,7 +113,7 @@ class RegistrationService 'created_at' => now(), ]); - if ($isParent && ! $noSecondInfo && ! empty($formatted['second_firstname'])) { + if ($isParent && !$noSecondInfo && !empty($formatted['second_firstname'])) { ParentModel::query()->create([ 'secondparent_firstname' => $formatted['second_firstname'] ?? null, 'secondparent_lastname' => $formatted['second_lastname'] ?? null, @@ -127,12 +128,12 @@ class RegistrationService }); $activationLink = $this->urls->spaRegistrationConfirmUrl($token); - $recipientName = trim((string) ($formatted['firstname'] ?? '').' '.(string) ($formatted['lastname'] ?? '')); + $recipientName = trim((string) ($formatted['firstname'] ?? '') . ' ' . (string) ($formatted['lastname'] ?? '')); - $html = '

Hello '.e($recipientName !== '' ? $recipientName : 'there').',

' - .'

Please confirm your email by clicking the link below:

' - .'

Activate your account

' - .'

Thank you.

'; + $html = '

Hello ' . e($recipientName !== '' ? $recipientName : 'there') . ',

' + . '

Please confirm your email by clicking the link below:

' + . '

Activate your account

' + . '

Thank you.

'; $sent = $this->emailService->send($email, 'Email Confirmation', $html, 'general'); $this->captchaService->clear(); diff --git a/app/Services/Auth/UserRoleService.php b/app/Services/Auth/UserRoleService.php index 1cf1a8a7..b1f8abc8 100644 --- a/app/Services/Auth/UserRoleService.php +++ b/app/Services/Auth/UserRoleService.php @@ -35,16 +35,16 @@ class UserRoleService return true; } - if ($crudAction === 'create' && ! empty($row->can_create)) { + if ($crudAction === 'create' && !empty($row->can_create)) { return true; } - if ($crudAction === 'read' && ! empty($row->can_read)) { + if ($crudAction === 'read' && !empty($row->can_read)) { return true; } - if ($crudAction === 'update' && ! empty($row->can_update)) { + if ($crudAction === 'update' && !empty($row->can_update)) { return true; } - if ($crudAction === 'delete' && ! empty($row->can_delete)) { + if ($crudAction === 'delete' && !empty($row->can_delete)) { return true; } } diff --git a/app/Services/BadgeScan/BadgeScanService.php b/app/Services/BadgeScan/BadgeScanService.php index fe137fe0..644437e8 100644 --- a/app/Services/BadgeScan/BadgeScanService.php +++ b/app/Services/BadgeScan/BadgeScanService.php @@ -2,14 +2,13 @@ namespace App\Services\BadgeScan; -use App\Controllers\View\RFIDController; use App\Models\Configuration; use App\Models\User; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; /** - * legacy {@see RFIDController} parity (badge scan + log listing). + * legacy {@see \App\Controllers\View\RFIDController} parity (badge scan + log listing). */ class BadgeScanService { diff --git a/app/Services/Badges/BadgeFormDataService.php b/app/Services/Badges/BadgeFormDataService.php index 0e982b60..cd76097c 100644 --- a/app/Services/Badges/BadgeFormDataService.php +++ b/app/Services/Badges/BadgeFormDataService.php @@ -8,7 +8,8 @@ class BadgeFormDataService protected BadgeUserLookupService $lookupService, protected BadgeStudentLookupService $studentLookupService, protected BadgeTextFormatter $formatter - ) {} + ) { + } public function build( ?string $schoolYear, @@ -23,7 +24,7 @@ class BadgeFormDataService $students = $this->studentLookupService->fetchStudentList($schoolYear, $selectedStudentIds); foreach ($users as &$u) { - if (! isset($u['user_id']) && isset($u['id'])) { + if (!isset($u['user_id']) && isset($u['id'])) { $u['user_id'] = (int) $u['id']; } @@ -45,7 +46,7 @@ class BadgeFormDataService $u['class_section_id'] = $u['class_section_id'] ?? null; $u['class_section_name'] = $u['class_section_name'] ?? null; $u['entity_type'] = 'user'; - $u['row_id'] = 'user:'.(int) ($u['user_id'] ?? 0); + $u['row_id'] = 'user:' . (int) ($u['user_id'] ?? 0); $u['role_group'] = $this->detectRoleGroup( strtolower((string) ($u['roles_raw'] ?? ($u['role_name_raw'] ?? ''))) ); @@ -56,7 +57,7 @@ class BadgeFormDataService $rolesDetect = strtolower((string) ($u['roles_raw'] ?? ($u['role_name_raw'] ?? ''))); $isTeacherish = str_contains($rolesDetect, 'teacher') || preg_match('/\bta\b/', $rolesDetect); - if ($isTeacherish && ! empty($u['user_id'])) { + if ($isTeacherish && !empty($u['user_id'])) { $assign = $this->lookupService->getLatestClassForUser((int) $u['user_id'], $schoolYear); if ($assign) { $u['class_section_id'] = $assign['class_section_id'] ?? null; @@ -68,7 +69,7 @@ class BadgeFormDataService foreach ($students as &$student) { $student['entity_type'] = 'student'; - $student['row_id'] = 'student:'.(int) ($student['student_id'] ?? 0); + $student['row_id'] = 'student:' . (int) ($student['student_id'] ?? 0); $student['role_group'] = 'student'; $student['class_section_id'] = null; @@ -83,17 +84,17 @@ class BadgeFormDataService $rows = array_merge($users, $students); usort($rows, static function (array $a, array $b): int { return strcasecmp( - trim((string) ($a['lastname'] ?? '')).' '.trim((string) ($a['firstname'] ?? '')), - trim((string) ($b['lastname'] ?? '')).' '.trim((string) ($b['firstname'] ?? '')) + trim((string) ($a['lastname'] ?? '')) . ' ' . trim((string) ($a['firstname'] ?? '')), + trim((string) ($b['lastname'] ?? '')) . ' ' . trim((string) ($b['firstname'] ?? '')) ); }); $rolesTabs = [ - 'all' => 'All', + 'all' => 'All', 'teacher' => 'Teachers', - 'ta' => 'Teacher Assistants', - 'admin' => 'Admins', - 'staff' => 'Staff', + 'ta' => 'Teacher Assistants', + 'admin' => 'Admins', + 'staff' => 'Staff', 'student' => 'Students', ]; @@ -102,13 +103,13 @@ class BadgeFormDataService : 'all'; return [ - 'users' => $rows, - 'schoolYears' => $this->lookupService->getAvailableSchoolYears(), - 'selectedYear' => $schoolYear, - 'selectedUserIds' => $selectedUserIds, + 'users' => $rows, + 'schoolYears' => $this->lookupService->getAvailableSchoolYears(), + 'selectedYear' => $schoolYear, + 'selectedUserIds' => $selectedUserIds, 'selectedStudentIds' => $selectedStudentIds, - 'rolesTabs' => $rolesTabs, - 'active_role' => $activeRole, + 'rolesTabs' => $rolesTabs, + 'active_role' => $activeRole, ]; } diff --git a/app/Services/Badges/BadgePdfService.php b/app/Services/Badges/BadgePdfService.php index 761020b3..20e7111f 100644 --- a/app/Services/Badges/BadgePdfService.php +++ b/app/Services/Badges/BadgePdfService.php @@ -33,13 +33,14 @@ class BadgePdfService protected BadgeUserLookupService $userLookupService, protected BadgePrintLogService $printLogService, protected BadgeTextFormatter $formatter, - ) {} + ) { + } /** * Letter landscape PDF, 8 badges per page — students and/or staff (FPDF + QR PNG). * * @param int[] $studentIds Primary keys on `students.id` - * @param int[] $userIds Staff/admin/teacher keys on `users.id` + * @param int[] $userIds Staff/admin/teacher keys on `users.id` */ public function generate( array $studentIds, @@ -85,7 +86,7 @@ class BadgePdfService try { $qrPayload = (string) ($staffRow['user_id_for_qr'] ?? $staffRow['user_id'] ?? ''); - if ($qrPayload === '' || ! preg_match('/^[A-Za-z0-9_-]+$/', $qrPayload)) { + if ($qrPayload === '' || !preg_match('/^[A-Za-z0-9_-]+$/', $qrPayload)) { $qrPayload = (string) (int) ($staffRow['user_id'] ?? 0); } @@ -143,7 +144,7 @@ class BadgePdfService ): string { $html = $this->buildHtmlDocument($rows, $schoolName, $motto, $footerBlock); - $options = new Options; + $options = new Options(); $options->set('isHtml5ParserEnabled', true); $options->set('isRemoteEnabled', true); $options->set('defaultFont', 'DejaVu Sans'); @@ -167,7 +168,7 @@ class BadgePdfService $this->tempQrFiles = []; try { - if (! class_exists('FPDF', false)) { + if (!class_exists('FPDF', false)) { require_once base_path('app/ThirdParty/fpdf/fpdf.php'); } @@ -199,7 +200,7 @@ class BadgePdfService for ($gridCol = 0; $gridCol < 4; $gridCol++) { $idx = ($gridRow * 4) + $gridCol; $row = $slots[$idx]; - if (! is_array($row)) { + if (!is_array($row)) { continue; } @@ -261,7 +262,7 @@ class BadgePdfService array $classesMap ): ?array { $info = $this->userLookupService->getUserInfoById($userId, $schoolYear); - if (! $info || ! is_array($info)) { + if (!$info || !is_array($info)) { return null; } @@ -275,7 +276,7 @@ class BadgePdfService $roleResolved = $this->formatter->formatRole($roleResolved); $info['role_resolved'] = $roleResolved; - if (! empty($classesMap[$resolvedId])) { + if (!empty($classesMap[$resolvedId])) { $info['class_section_name'] = (string) $classesMap[$resolvedId]; } @@ -290,11 +291,11 @@ class BadgePdfService if ($isTeacherish && $class !== '') { if (strtolower($class) === 'youth') { - $display = 'Youth '.$roleResolved; + $display = 'Youth ' . $roleResolved; } elseif ($class === 'KG') { - $display = 'KG '.$roleResolved; + $display = 'KG ' . $roleResolved; } else { - $display = 'Grade '.$class.' '.$roleResolved; + $display = 'Grade ' . $class . ' ' . $roleResolved; } } elseif ($roleResolved !== '') { $display = $roleResolved; @@ -308,7 +309,7 @@ class BadgePdfService $year = $this->formatter->norm((string) ($info['school_year'] ?? ($schoolYear ?? ''))); $schoolId = trim((string) ($info['school_id'] ?? '')); - if ($schoolId === '' || ! preg_match('/^[A-Za-z0-9_-]+$/', $schoolId)) { + if ($schoolId === '' || !preg_match('/^[A-Za-z0-9_-]+$/', $schoolId)) { return null; } @@ -363,10 +364,10 @@ class BadgePdfService } return 'Badges PDF' - .$badgesHtml - .''; + . $this->badgeCss() + . '' + . $badgesHtml + . ''; } protected function buildBadgeHtml( @@ -375,7 +376,8 @@ class BadgePdfService string $motto, string $footerBlock, ?string $logoDataUri - ): string { + ): string + { $kind = (string) ($row['_badge_kind'] ?? 'student'); $idLabel = $kind === 'staff' ? 'User ID' : 'School ID'; $title = $this->escapeHtml((string) ($row['fullname'] ?? '')); @@ -402,8 +404,8 @@ class BadgePdfService
G - '.$gradeLabel.' - '.$grade.' + ' . $gradeLabel . ' + ' . $grade . '
'; } @@ -413,15 +415,15 @@ class BadgePdfService Y Academic Year - '.$year.' + ' . $year . '
ID - '.$this->escapeHtml($idLabel).' - '.$schoolId.' + ' . $this->escapeHtml($idLabel) . ' + ' . $schoolId . '
'; @@ -430,18 +432,18 @@ class BadgePdfService
' - .($logoDataUri !== null - ? 'School Logo' - : 'AS'). + . ($logoDataUri !== null + ? 'School Logo' + : 'AS') . '
-
'.$this->escapeHtml($headerMainTitle).'
- '.($schoolLevel !== '' - ? '
'.$this->escapeHtml($schoolLevel).'
' - : '').' - '.($headerMotto !== '' - ? '
'.$this->escapeHtml($headerMotto).'
' - : '').' +
' . $this->escapeHtml($headerMainTitle) . '
+ ' . ($schoolLevel !== '' + ? '
' . $this->escapeHtml($schoolLevel) . '
' + : '') . ' + ' . ($headerMotto !== '' + ? '
' . $this->escapeHtml($headerMotto) . '
' + : '') . '
@@ -449,25 +451,25 @@ class BadgePdfService
-
'.mb_strtoupper($title, 'UTF-8').'
+
' . mb_strtoupper($title, 'UTF-8') . '
-
'.mb_strtoupper($role, 'UTF-8').'
+
' . mb_strtoupper($role, 'UTF-8') . '
@@ -475,18 +477,18 @@ class BadgePdfService
- '.$infoRows.' + ' . $infoRows . '
' - .($qrSrc !== '' - ? 'QR Code' - : ''). + . ($qrSrc !== '' + ? 'QR Code' + : '') . '
Scan to verify
-
'.$this->buildBarcodeHtml($barcodeValue).'
-
'.$barcodeText.'
+
' . $this->buildBarcodeHtml($barcodeValue) . '
+
' . $barcodeText . '
'; @@ -897,7 +899,7 @@ CSS; default => '4px', }; - $bars[] = ''; + $bars[] = ''; $bars[] = ''; } @@ -915,7 +917,7 @@ CSS; return null; } - $tmpPath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'badge_qr_'.bin2hex(random_bytes(8)).'.png'; + $tmpPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'badge_qr_' . bin2hex(random_bytes(8)) . '.png'; if (@file_put_contents($tmpPath, $png) === false) { return null; } @@ -1000,11 +1002,11 @@ CSS; { return $this->formatter->firstExisting([ public_path($filename), - public_path('badges/'.$filename), - public_path('assets/images/'.$filename), - public_path('assets/images/badges/'.$filename), - storage_path('app/public/'.$filename), - storage_path('app/public/badges/'.$filename), + public_path('badges/' . $filename), + public_path('assets/images/' . $filename), + public_path('assets/images/badges/' . $filename), + storage_path('app/public/' . $filename), + storage_path('app/public/badges/' . $filename), ]); } @@ -1085,7 +1087,7 @@ CSS; /** * Shrink text until it fits in the available width. FPDF, bravely, does not do this for us. * - * @param array{0:int,1:int,2:int} $rgb + * @param array{0:int,1:int,2:int} $rgb */ protected function fitCenteredText( \FPDF $pdf, @@ -1147,7 +1149,7 @@ CSS; } /** - * @param array{0:int,1:int,2:int} $rgb + * @param array{0:int,1:int,2:int} $rgb */ protected function fitLeftText( \FPDF $pdf, @@ -1445,7 +1447,6 @@ CSS; foreach ($segments as [$type, $segmentWidth]) { if ($type === 'gap') { $cursor += $segmentWidth; - continue; } @@ -1509,7 +1510,7 @@ CSS; protected function preparedLogoPath(): ?string { $path = $this->logoFilePath(); - if ($path === null || ! is_readable($path)) { + if ($path === null || !is_readable($path)) { return null; } @@ -1518,7 +1519,7 @@ CSS; return $path; } - $tmpPath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'badge_logo_'.bin2hex(random_bytes(8)).'.png'; + $tmpPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'badge_logo_' . bin2hex(random_bytes(8)) . '.png'; if (@file_put_contents($tmpPath, $png) === false) { return $path; } @@ -1531,7 +1532,7 @@ CSS; protected function logoDataUri(): ?string { $path = $this->logoFilePath(); - if ($path === null || ! is_readable($path)) { + if ($path === null || !is_readable($path)) { return null; } @@ -1543,9 +1544,10 @@ CSS; return null; } - return 'data:image/png;base64,'.base64_encode($bytes); + return 'data:image/png;base64,' . base64_encode($bytes); } + protected function headerMainTitle(string $schoolName): string { $name = trim($schoolName) !== '' ? trim($schoolName) : 'Al Rahma Sunday School'; @@ -1577,7 +1579,7 @@ CSS; { $address = trim((string) config('badges.footer_address', '')); if ($address !== '') { - return $schoolName."\n".$address; + return $schoolName . "\n" . $address; } return $schoolName; @@ -1585,7 +1587,7 @@ CSS; protected function makeCircularPngBytesFromPath(string $path): ?string { - if (! function_exists('imagecreatetruecolor') || ! function_exists('imagepng')) { + if (!function_exists('imagecreatetruecolor') || !function_exists('imagepng')) { return null; } @@ -1624,7 +1626,6 @@ CSS; $circle = imagecreatetruecolor($size, $size); if ($circle === false) { imagedestroy($square); - return null; } diff --git a/app/Services/Badges/BadgePrintLogService.php b/app/Services/Badges/BadgePrintLogService.php index 25fd6da3..e820f4ad 100644 --- a/app/Services/Badges/BadgePrintLogService.php +++ b/app/Services/Badges/BadgePrintLogService.php @@ -10,7 +10,8 @@ class BadgePrintLogService public function __construct( protected BadgePrintLog $badgePrintLogModel, protected BadgeTextFormatter $formatter - ) {} + ) { + } public function getStatus(array $userIds, ?string $schoolYear): array { @@ -50,7 +51,7 @@ class BadgePrintLogService try { $this->log($userIds, $actorId, $schoolYear, $rolesMap, $classesMap, $copies); } catch (\Throwable $e) { - Log::error('Failed to log badge prints: '.$e->getMessage()); + Log::error('Failed to log badge prints: ' . $e->getMessage()); } } -} +} \ No newline at end of file diff --git a/app/Services/Badges/BadgeService.php b/app/Services/Badges/BadgeService.php index c2bb7224..fdbcfb4c 100644 --- a/app/Services/Badges/BadgeService.php +++ b/app/Services/Badges/BadgeService.php @@ -23,7 +23,8 @@ class BadgeService protected TeacherClass $teacherClassModel, protected ClassSection $classSectionModel, protected BadgePrintLog $badgePrintLogModel - ) {} + ) { + } public function generateBadgePdf( array $userIds, @@ -54,7 +55,7 @@ class BadgeService foreach ($userIds as $uid) { $info = $this->getUserInfoById($uid, $schoolYear); - if (! $info || ! is_array($info)) { + if (!$info || !is_array($info)) { continue; } @@ -69,13 +70,13 @@ class BadgeService $roleResolved = $this->formatRole($roleResolved); $info['role_resolved'] = $roleResolved; - if (! empty($classesMap[$userId])) { + if (!empty($classesMap[$userId])) { $info['class_section_name'] = (string) $classesMap[$userId]; } $class = $this->norm($info['class_section_name'] ?? ''); - $badgeKey = strtolower(trim($userId.'|'.$name.'|'.$roleResolved.'|'.$class)); + $badgeKey = strtolower(trim($userId . '|' . $name . '|' . $roleResolved . '|' . $class)); if (isset($seen[$badgeKey])) { continue; } @@ -116,7 +117,7 @@ class BadgeService 1 ); } catch (\Throwable $e) { - Log::error('Failed to log badge prints: '.$e->getMessage()); + Log::error('Failed to log badge prints: ' . $e->getMessage()); } return response($pdfString, 200, [ @@ -158,7 +159,7 @@ class BadgeService $users = $this->fetchStaffList($schoolYear, $selectedUserIds); foreach ($users as &$u) { - if (! isset($u['user_id'])) { + if (!isset($u['user_id'])) { if (isset($u['id'])) { $u['user_id'] = (int) $u['id']; } @@ -189,7 +190,7 @@ class BadgeService $rolesDetect = strtolower($u['roles_raw'] ?? ($u['role_name_raw'] ?? '')); $isTeacherish = str_contains($rolesDetect, 'teacher') || preg_match('/\bta\b/', $rolesDetect); - if ($isTeacherish && ! empty($u['user_id'])) { + if ($isTeacherish && !empty($u['user_id'])) { $assign = $this->getLatestClassForUser((int) $u['user_id'], $schoolYear); if ($assign) { $u['class_section_id'] = $assign['class_section_id'] ?? null; @@ -233,11 +234,11 @@ class BadgeService ]) ->groupBy('users.id', 'users.firstname', 'users.lastname'); - if (! empty($selectedUserIds)) { + if (!empty($selectedUserIds)) { $query->whereIn('users.id', $selectedUserIds); } - if (! empty($schoolYear) && Schema::hasColumn('user_roles', 'school_year')) { + if (!empty($schoolYear) && Schema::hasColumn('user_roles', 'school_year')) { $query->where('user_roles.school_year', $schoolYear); } @@ -254,7 +255,7 @@ class BadgeService ]) ->where('tc.teacher_id', $userId); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $query->where('tc.school_year', $schoolYear); } @@ -264,7 +265,7 @@ class BadgeService ->orderByDesc('tc.id') ->first(); - if (! $row || empty($row->class_section_id)) { + if (!$row || empty($row->class_section_id)) { return null; } @@ -281,12 +282,12 @@ class BadgeService ->where('id', $id) ->first(); - if (! $u) { + if (!$u) { return null; } $userId = (int) $u->user_id; - $fullname = trim(($u->firstname ?? '').' '.($u->lastname ?? '')); + $fullname = trim(($u->firstname ?? '') . ' ' . ($u->lastname ?? '')); $rolesRows = DB::table('user_roles as ur') ->join('roles as r', 'r.id', '=', 'ur.role_id') @@ -309,7 +310,7 @@ class BadgeService ->select(['class_section_id', 'updated_at', 'id', 'position', 'school_year']) ->where('teacher_id', $userId); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $tcQuery->where('school_year', $schoolYear); } @@ -321,7 +322,7 @@ class BadgeService $position = strtolower(trim((string) ($assignment->position ?? ''))); $className = null; - if (! empty($classId)) { + if (!empty($classId)) { $className = $this->resolveClassName((int) $classId); } @@ -329,7 +330,7 @@ class BadgeService $roleLabel = 'Teacher Assistant'; } elseif ($position === 'teacher' || $position === 'main') { $roleLabel = 'Teacher'; - } elseif (! empty($allRoles)) { + } elseif (!empty($allRoles)) { $roleLabel = $allRoles[0]; } else { $roleLabel = 'Staff'; @@ -346,11 +347,11 @@ class BadgeService ]); $jobTitle = ''; - if (! empty($roleLabel) && ! empty($className)) { + if (!empty($roleLabel) && !empty($className)) { $jobTitle = "{$roleLabel} - {$className}"; - } elseif (! empty($roleLabel)) { + } elseif (!empty($roleLabel)) { $jobTitle = $roleLabel; - } elseif (! empty($className)) { + } elseif (!empty($className)) { $jobTitle = $className; } @@ -378,10 +379,10 @@ class BadgeService $pdf->Rect($x, $y, $w, $h); $logoSize = 6; - if (! empty($data['school_logo']) && file_exists($data['school_logo'])) { + if (!empty($data['school_logo']) && file_exists($data['school_logo'])) { $pdf->Image($data['school_logo'], $x + $w - 6 - $logoSize, $y + 4, $logoSize + 3, $logoSize - 1); } - if (! empty($data['isgl_logo']) && file_exists($data['isgl_logo'])) { + if (!empty($data['isgl_logo']) && file_exists($data['isgl_logo'])) { $pdf->Image($data['isgl_logo'], $x + 4, $y + 4, $logoSize + 3, $logoSize - 1); } @@ -417,11 +418,11 @@ class BadgeService if ($isTeacherish && $class !== '') { if (strtolower($class) === 'youth') { - $display = 'Youth '.$roleResolved; + $display = 'Youth ' . $roleResolved; } elseif ($class === 'KG') { - $display = 'KG '.$roleResolved; + $display = 'KG ' . $roleResolved; } else { - $display = 'Grade '.$class.' '.$roleResolved; + $display = 'Grade ' . $class . ' ' . $roleResolved; } } elseif ($roleResolved !== '') { $display = $roleResolved; @@ -460,7 +461,7 @@ class BadgeService 'role', 'active_role', 'role_name', - fn ($r) => ! empty($r['roles']) + fn ($r) => !empty($r['roles']) ? (array_filter(array_map('trim', explode(',', (string) $r['roles'])))[0] ?? '') : '', 'job_title', @@ -478,7 +479,7 @@ class BadgeService return $this->norm($v); } } else { - if (! empty($info[$key])) { + if (!empty($info[$key])) { $v = $this->norm((string) $info[$key]); if ($v !== '') { return $v; @@ -578,7 +579,6 @@ class BadgeService if ($start === false) { $out[] = ucfirst(mb_strtolower($tok, 'UTF-8')); - continue; } @@ -594,12 +594,12 @@ class BadgeService $coreFmt = preg_replace_callback( '/\p{L}+/u', static fn ($m) => mb_strtoupper(mb_substr($m[0], 0, 1, 'UTF-8'), 'UTF-8') - .mb_strtolower(mb_substr($m[0], 1, null, 'UTF-8'), 'UTF-8'), + . mb_strtolower(mb_substr($m[0], 1, null, 'UTF-8'), 'UTF-8'), mb_strtolower($core, 'UTF-8') ); } - $out[] = $pre.$coreFmt.$suf; + $out[] = $pre . $coreFmt . $suf; } return implode(' ', $out); @@ -640,7 +640,7 @@ class BadgeService protected function firstExisting(array $paths): ?string { foreach ($paths as $path) { - if (! empty($path) && file_exists($path)) { + if (!empty($path) && file_exists($path)) { return $path; } } @@ -697,4 +697,4 @@ class BadgeService return $schoolYears; } -} +} \ No newline at end of file diff --git a/app/Services/Badges/BadgeStudentLookupService.php b/app/Services/Badges/BadgeStudentLookupService.php index e8c4473a..ea519b0a 100644 --- a/app/Services/Badges/BadgeStudentLookupService.php +++ b/app/Services/Badges/BadgeStudentLookupService.php @@ -12,7 +12,8 @@ class BadgeStudentLookupService { public function __construct( protected BadgeTextFormatter $formatter - ) {} + ) { + } /** * Active student roster for the badge picker. @@ -28,7 +29,7 @@ class BadgeStudentLookupService ->leftJoin('student_class as sc', function ($join) use ($schoolYear) { $join->on('sc.student_id', '=', 'students.id'); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $join->where('sc.school_year', '=', $schoolYear); } }) @@ -54,9 +55,9 @@ class BadgeStudentLookupService ->orderBy('students.lastname') ->orderBy('students.firstname'); - if (! empty($selectedStudentIds)) { + if (!empty($selectedStudentIds)) { $query->whereIn('students.id', $selectedStudentIds); - } elseif (! empty($schoolYear)) { + } elseif (!empty($schoolYear)) { $query->where(function ($q) use ($schoolYear) { $q->where('students.school_year', $schoolYear) ->orWhereNotNull('sc.student_id'); @@ -73,7 +74,7 @@ class BadgeStudentLookupService } $schoolId = trim((string) ($row['school_id'] ?? '')); - if ($schoolId === '' || ! preg_match('/^[A-Za-z0-9_-]+$/', $schoolId)) { + if ($schoolId === '' || !preg_match('/^[A-Za-z0-9_-]+$/', $schoolId)) { continue; } @@ -116,7 +117,7 @@ class BadgeStudentLookupService $out = []; foreach ($rows as $student) { $schoolId = trim((string) ($student->school_id ?? '')); - if ($schoolId === '' || ! preg_match('/^[A-Za-z0-9_-]+$/', $schoolId)) { + if ($schoolId === '' || !preg_match('/^[A-Za-z0-9_-]+$/', $schoolId)) { continue; } diff --git a/app/Services/Badges/BadgeTextFormatter.php b/app/Services/Badges/BadgeTextFormatter.php index 1336def0..2e72731d 100644 --- a/app/Services/Badges/BadgeTextFormatter.php +++ b/app/Services/Badges/BadgeTextFormatter.php @@ -78,7 +78,7 @@ class BadgeTextFormatter } $special = [ - 'of' => 'of', + 'of' => 'of', 'head' => 'Head', ]; @@ -95,7 +95,6 @@ class BadgeTextFormatter if ($start === false) { $out[] = ucfirst(mb_strtolower($tok, 'UTF-8')); - continue; } @@ -111,12 +110,12 @@ class BadgeTextFormatter $coreFmt = preg_replace_callback( '/\p{L}+/u', static fn ($m) => mb_strtoupper(mb_substr($m[0], 0, 1, 'UTF-8'), 'UTF-8') - .mb_strtolower(mb_substr($m[0], 1, null, 'UTF-8'), 'UTF-8'), + . mb_strtolower(mb_substr($m[0], 1, null, 'UTF-8'), 'UTF-8'), mb_strtolower($core, 'UTF-8') ); } - $out[] = $pre.$coreFmt.$suf; + $out[] = $pre . $coreFmt . $suf; } return implode(' ', $out); @@ -164,7 +163,7 @@ class BadgeTextFormatter 'role', 'active_role', 'role_name', - fn ($r) => ! empty($r['roles']) + fn ($r) => !empty($r['roles']) ? (array_values(array_filter(array_map('trim', explode(',', (string) $r['roles']))))[0] ?? '') : '', 'job_title', @@ -182,7 +181,7 @@ class BadgeTextFormatter return $this->norm($v); } } else { - if (! empty($info[$key])) { + if (!empty($info[$key])) { $v = $this->norm((string) $info[$key]); if ($v !== '') { return $v; @@ -197,7 +196,7 @@ class BadgeTextFormatter public function firstExisting(array $paths): ?string { foreach ($paths as $path) { - if (! empty($path) && file_exists($path)) { + if (!empty($path) && file_exists($path)) { return $path; } } diff --git a/app/Services/Badges/BadgeUserLookupService.php b/app/Services/Badges/BadgeUserLookupService.php index 6e501b32..f9ff53e6 100644 --- a/app/Services/Badges/BadgeUserLookupService.php +++ b/app/Services/Badges/BadgeUserLookupService.php @@ -9,7 +9,8 @@ class BadgeUserLookupService { public function __construct( protected BadgeTextFormatter $formatter - ) {} + ) { + } public function fetchStaffList(?string $schoolYear, array $selectedUserIds = []): array { @@ -24,7 +25,7 @@ class BadgeUserLookupService ]) ->groupBy('users.id', 'users.firstname', 'users.lastname'); - if (! empty($selectedUserIds)) { + if (!empty($selectedUserIds)) { $query->whereIn('users.id', $selectedUserIds); } @@ -64,7 +65,7 @@ class BadgeUserLookupService ]) ->where('tc.teacher_id', $userId); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $query->where('tc.school_year', $schoolYear); } @@ -74,12 +75,12 @@ class BadgeUserLookupService ->orderByDesc('tc.id') ->first(); - if (! $row || empty($row->class_section_id)) { + if (!$row || empty($row->class_section_id)) { return null; } return [ - 'class_section_id' => (int) $row->class_section_id, + 'class_section_id' => (int) $row->class_section_id, 'class_section_name' => $row->class_section_name ?? null, ]; } @@ -91,12 +92,12 @@ class BadgeUserLookupService ->where('id', $id) ->first(); - if (! $u) { + if (!$u) { return null; } $userId = (int) $u->user_id; - $fullname = trim(($u->firstname ?? '').' '.($u->lastname ?? '')); + $fullname = trim(($u->firstname ?? '') . ' ' . ($u->lastname ?? '')); $schoolId = trim((string) ($u->school_id ?? '')); if ($schoolId === '') { $schoolId = trim((string) ($u->account_id ?? '')); @@ -123,7 +124,7 @@ class BadgeUserLookupService ->select(['class_section_id', 'updated_at', 'id', 'position', 'school_year']) ->where('teacher_id', $userId); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $tcQuery->where('school_year', $schoolYear); } @@ -135,7 +136,7 @@ class BadgeUserLookupService $position = strtolower(trim((string) ($assignment->position ?? ''))); $className = null; - if (! empty($classId)) { + if (!empty($classId)) { $className = $this->resolveClassName((int) $classId); } @@ -143,7 +144,7 @@ class BadgeUserLookupService $roleLabel = 'Teacher Assistant'; } elseif ($position === 'teacher' || $position === 'main') { $roleLabel = 'Teacher'; - } elseif (! empty($allRoles)) { + } elseif (!empty($allRoles)) { $roleLabel = $allRoles[0]; } else { $roleLabel = 'Staff'; @@ -160,27 +161,27 @@ class BadgeUserLookupService ]); $jobTitle = ''; - if (! empty($roleLabel) && ! empty($className)) { + if (!empty($roleLabel) && !empty($className)) { $jobTitle = "{$roleLabel} - {$className}"; - } elseif (! empty($roleLabel)) { + } elseif (!empty($roleLabel)) { $jobTitle = $roleLabel; - } elseif (! empty($className)) { + } elseif (!empty($className)) { $jobTitle = $className; } return [ - 'user_id' => $userId, - 'name' => $fullname !== '' ? $fullname : 'STAFF', - 'role' => $roleLabel, - 'roles' => $rolesCsv, - 'class_section_id' => $classId ? (int) $classId : null, - 'class_section_name' => $className, - 'job_title' => $jobTitle, - 'school_name' => 'Al Rahma Sunday School', - 'school_id' => $schoolId, - 'school_logo' => $schoolLogo, - 'isgl_logo' => $isglLogo, - 'school_year' => $assignment->school_year ?? $schoolYear, + 'user_id' => $userId, + 'name' => $fullname !== '' ? $fullname : 'STAFF', + 'role' => $roleLabel, + 'roles' => $rolesCsv, + 'class_section_id' => $classId ? (int) $classId : null, + 'class_section_name' => $className, + 'job_title' => $jobTitle, + 'school_name' => 'Al Rahma Sunday School', + 'school_id' => $schoolId, + 'school_logo' => $schoolLogo, + 'isgl_logo' => $isglLogo, + 'school_year' => $assignment->school_year ?? $schoolYear, ]; } diff --git a/app/Services/Billing/BalanceCalculationService.php b/app/Services/Billing/BalanceCalculationService.php index 2d3a4a46..46ca0a0b 100644 --- a/app/Services/Billing/BalanceCalculationService.php +++ b/app/Services/Billing/BalanceCalculationService.php @@ -21,10 +21,12 @@ class BalanceCalculationService private FeeConfigService $config, private TuitionCalculationService $tuition, private BillingTotalsService $billingTotals - ) {} + ) { + } /** - * @param array> $students + * @param array> $students + * * @return array */ public function calculateFamilyAccount(array $students, int $parentId, ?string $schoolYear = null): array @@ -96,8 +98,9 @@ class BalanceCalculationService } /** - * @param array> $tuitionStudents - * @param array $eventByStudent + * @param array> $tuitionStudents + * @param array $eventByStudent + * * @return array> */ private function buildStudentBalances( diff --git a/app/Services/Billing/BillingTotalsService.php b/app/Services/Billing/BillingTotalsService.php index b08188dc..92ce9a6c 100644 --- a/app/Services/Billing/BillingTotalsService.php +++ b/app/Services/Billing/BillingTotalsService.php @@ -96,7 +96,7 @@ class BillingTotalsService } /** - * @param array $rows + * @param array $rows */ private function sumAdditionalChargeRows(array $rows): float { diff --git a/app/Services/Billing/ChargeService.php b/app/Services/Billing/ChargeService.php index 9167a7a3..6c2125ef 100644 --- a/app/Services/Billing/ChargeService.php +++ b/app/Services/Billing/ChargeService.php @@ -26,7 +26,8 @@ class ChargeService private ExtraChargesInvoiceService $invoices, private ExtraChargesContextService $context, private InvoiceGenerationService $invoiceGeneration - ) {} + ) { + } public function createExtraCharge(array $payload): array { @@ -59,7 +60,7 @@ class ChargeService 'semester' => $payload['semester'] ?? $this->context->getSemester(), ])); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $result; } @@ -69,14 +70,14 @@ class ChargeService 'id' => (int) ($result['id'] ?? 0), 'parent_id' => $parentId, 'invoice_id' => $result['invoice_id'] ?? null, - 'status' => ! empty($payload['invoice_id']) ? 'applied' : 'pending', + 'status' => !empty($payload['invoice_id']) ? 'applied' : 'pending', ]; } public function cancelExtraCharge(int $chargeId): array { $charge = AdditionalCharge::query()->find($chargeId); - if (! $charge) { + if (!$charge) { return ['ok' => false, 'message' => 'Extra charge not found.']; } @@ -98,7 +99,7 @@ class ChargeService public function applyExtraCharge(int $chargeId, int $invoiceId): array { $charge = AdditionalCharge::query()->find($chargeId); - if (! $charge) { + if (!$charge) { return ['ok' => false, 'message' => 'Extra charge not found.']; } @@ -164,7 +165,7 @@ class ChargeService $amount = isset($payload['amount']) ? (float) $payload['amount'] : null; if ($eventId > 0) { $event = Event::getEvent($eventId, $schoolYear); - if (! $event) { + if (!$event) { return ['ok' => false, 'message' => 'Event not found.']; } $eventName = (string) ($event->event_name ?? $eventName); @@ -224,7 +225,7 @@ class ChargeService public function cancelEventCharge(int $chargeId, bool $issueCredit = true): array { $charge = EventCharges::query()->find($chargeId); - if (! $charge) { + if (!$charge) { return ['ok' => false, 'message' => 'Event charge not found.']; } @@ -251,8 +252,8 @@ class ChargeService if ($issueCredit && $amount > 0 && $parentId > 0) { $credit = $this->createExtraCharge([ 'parent_id' => $parentId, - 'title' => 'Event credit: '.$eventName, - 'description' => 'Account credit for canceled event charge #'.$chargeId, + 'title' => 'Event credit: ' . $eventName, + 'description' => 'Account credit for canceled event charge #' . $chargeId, 'amount' => $amount, 'charge_type' => 'deduct', 'school_year' => $schoolYear, @@ -286,7 +287,7 @@ class ChargeService public function markEventChargePaid(int $chargeId, bool $paid, ?int $paymentId = null): array { $charge = EventCharges::query()->find($chargeId); - if (! $charge) { + if (!$charge) { return ['ok' => false, 'message' => 'Event charge not found.']; } @@ -388,7 +389,7 @@ class ChargeService private function resolveEventName(EventCharges $charge): string { - if (! empty($charge->event_name)) { + if (!empty($charge->event_name)) { return (string) $charge->event_name; } @@ -425,7 +426,7 @@ class ChargeService } /** - * @param array $row + * @param array $row */ private function formatEventCharge(array $row): array { diff --git a/app/Services/BroadcastEmail/BroadcastEmailComposerService.php b/app/Services/BroadcastEmail/BroadcastEmailComposerService.php index cc58abcb..a0361dd3 100644 --- a/app/Services/BroadcastEmail/BroadcastEmailComposerService.php +++ b/app/Services/BroadcastEmail/BroadcastEmailComposerService.php @@ -11,7 +11,6 @@ class BroadcastEmailComposerService $html = preg_replace('#<(script|iframe)[^>]*>.*?#is', '', $html); $html = preg_replace('/\\son\\w+="[^"]*"/i', '', $html); $html = preg_replace("/\\son\\w+='[^']*'/i", '', $html); - return $html ?? ''; } @@ -27,7 +26,7 @@ class BroadcastEmailComposerService ): string { $content = $personalize ? str_replace('{{name}}', $recipientName, $body) : $body; - if (! $wrapLayout) { + if (!$wrapLayout) { return $content; } diff --git a/app/Services/BroadcastEmail/BroadcastEmailDispatchService.php b/app/Services/BroadcastEmail/BroadcastEmailDispatchService.php index a7f2c3f9..5962317c 100644 --- a/app/Services/BroadcastEmail/BroadcastEmailDispatchService.php +++ b/app/Services/BroadcastEmail/BroadcastEmailDispatchService.php @@ -7,7 +7,6 @@ use App\Services\EmailService; class BroadcastEmailDispatchService { private EmailService $mailer; - private BroadcastEmailComposerService $composer; public function __construct(EmailService $mailer, BroadcastEmailComposerService $composer) @@ -31,7 +30,7 @@ class BroadcastEmailDispatchService $ok = $this->mailer->send( $payload['test_email'], - '[TEST] '.$payload['subject'], + '[TEST] ' . $payload['subject'], $html, $payload['from_key'] ); diff --git a/app/Services/BroadcastEmail/BroadcastEmailImageService.php b/app/Services/BroadcastEmail/BroadcastEmailImageService.php index 255f2026..eddac183 100644 --- a/app/Services/BroadcastEmail/BroadcastEmailImageService.php +++ b/app/Services/BroadcastEmail/BroadcastEmailImageService.php @@ -26,7 +26,7 @@ class BroadcastEmailImageService } $mime = strtolower((string) $file->getMimeType()); - if (! isset($this->allowedTypes[$mime])) { + if (!isset($this->allowedTypes[$mime])) { return [ 'ok' => false, 'status' => 415, @@ -43,17 +43,17 @@ class BroadcastEmailImageService } $targetDir = public_path('uploads/email'); - if (! is_dir($targetDir)) { + if (!is_dir($targetDir)) { @mkdir($targetDir, 0755, true); } $ext = $this->allowedTypes[$mime]; - $newName = 'em_'.bin2hex(random_bytes(16)).'.'.$ext; + $newName = 'em_' . bin2hex(random_bytes(16)) . '.' . $ext; $file->move($targetDir, $newName); return [ 'ok' => true, - 'url' => asset('uploads/email/'.$newName), + 'url' => asset('uploads/email/' . $newName), ]; } } diff --git a/app/Services/BroadcastEmail/BroadcastEmailRecipientService.php b/app/Services/BroadcastEmail/BroadcastEmailRecipientService.php index 10cd1630..0649ef0a 100644 --- a/app/Services/BroadcastEmail/BroadcastEmailRecipientService.php +++ b/app/Services/BroadcastEmail/BroadcastEmailRecipientService.php @@ -13,7 +13,6 @@ class BroadcastEmailRecipientService return array_values(array_filter($parents, static function ($parent) { $email = $parent['email'] ?? ''; - return is_string($email) && trim($email) !== ''; })); } diff --git a/app/Services/BroadcastEmail/BroadcastEmailSenderOptionsService.php b/app/Services/BroadcastEmail/BroadcastEmailSenderOptionsService.php index dde00441..294458b8 100644 --- a/app/Services/BroadcastEmail/BroadcastEmailSenderOptionsService.php +++ b/app/Services/BroadcastEmail/BroadcastEmailSenderOptionsService.php @@ -9,13 +9,12 @@ class BroadcastEmailSenderOptionsService $json = getenv('MAIL_SENDERS') ?: env('MAIL_SENDERS', '{}'); $arr = json_decode($json, true); - if (! is_array($arr) || empty($arr)) { + if (!is_array($arr) || empty($arr)) { $smtpUser = getenv('SMTP_USER') ?: ''; $name = 'Al Rahma Sunday School'; - return [[ 'key' => 'general', - 'label' => $name.($smtpUser ? " <{$smtpUser}>" : ''), + 'label' => $name . ($smtpUser ? " <{$smtpUser}>" : ''), ]]; } @@ -25,7 +24,7 @@ class BroadcastEmailSenderOptionsService $email = $info['email'] ?? ''; $out[] = [ 'key' => (string) $key, - 'label' => trim($name.($email ? " <{$email}>" : '')), + 'label' => trim($name . ($email ? " <{$email}>" : '')), ]; } diff --git a/app/Services/Certificates/CertificateAdminService.php b/app/Services/Certificates/CertificateAdminService.php index 82540f38..52e8668d 100644 --- a/app/Services/Certificates/CertificateAdminService.php +++ b/app/Services/Certificates/CertificateAdminService.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Services\Certificates; +use App\Models\CertificateRecord; use App\Models\Configuration; use App\Models\StudentDecision; use Illuminate\Support\Facades\DB; @@ -640,7 +641,6 @@ class CertificateAdminService if (preg_match('/grade\s*(\d+)/i', $name, $matches) === 1) { $grade = (int) $matches[1]; - return [ 'Grade '.$grade, '1_'.str_pad((string) $grade, 3, '0', STR_PAD_LEFT), diff --git a/app/Services/Certificates/CertificatePdfService.php b/app/Services/Certificates/CertificatePdfService.php index c07690f9..8bc5cce2 100644 --- a/app/Services/Certificates/CertificatePdfService.php +++ b/app/Services/Certificates/CertificatePdfService.php @@ -7,13 +7,12 @@ namespace App\Services\Certificates; class CertificatePdfService { private string $fontDir; - private string $imgDir; public function __construct() { - $this->fontDir = public_path('assets/certificates/fonts').DIRECTORY_SEPARATOR; - $this->imgDir = public_path('assets/certificates/images').DIRECTORY_SEPARATOR; + $this->fontDir = public_path('assets/certificates/fonts') . DIRECTORY_SEPARATOR; + $this->imgDir = public_path('assets/certificates/images') . DIRECTORY_SEPARATOR; } /** @@ -21,9 +20,9 @@ class CertificatePdfService */ public function generate(array $students, string $certDate): string { - $edwardianFont = \TCPDF_FONTS::addTTFfont($this->fontDir.'Edwardian Script ITC Regular.ttf', 'TrueTypeUnicode', '', 32); - $garamondBold = \TCPDF_FONTS::addTTFfont($this->fontDir.'Garamond Bold.ttf', 'TrueTypeUnicode', '', 32); - $ebGaramond = \TCPDF_FONTS::addTTFfont($this->fontDir.'EBGaramond-Regular.ttf', 'TrueTypeUnicode', '', 32); + $edwardianFont = \TCPDF_FONTS::addTTFfont($this->fontDir . 'Edwardian Script ITC Regular.ttf', 'TrueTypeUnicode', '', 32); + $garamondBold = \TCPDF_FONTS::addTTFfont($this->fontDir . 'Garamond Bold.ttf', 'TrueTypeUnicode', '', 32); + $ebGaramond = \TCPDF_FONTS::addTTFfont($this->fontDir . 'EBGaramond-Regular.ttf', 'TrueTypeUnicode', '', 32); $pdf = new \TCPDF('L', 'pt', 'A4', true, 'UTF-8', false); $pdf->SetCreator('Al Rahma Sunday School'); @@ -40,7 +39,7 @@ class CertificatePdfService foreach ($students as $student) { $pdf->AddPage(); - $name = $student['firstname'].' '.$student['lastname']; + $name = $student['firstname'] . ' ' . $student['lastname']; $grade = $this->formatGrade((string) ($student['grade'] ?? '')); $certNumber = (string) ($student['cert_number'] ?? ''); $verifyUrl = is_string($student['verify_url'] ?? null) ? $student['verify_url'] : null; @@ -65,8 +64,8 @@ class CertificatePdfService private function drawCertificate( \TCPDF $pdf, - float $W, - float $H, + float $W, + float $H, string $name, string $grade, string $certDate, @@ -76,9 +75,9 @@ class CertificatePdfService string $garamondBold, string $ebGaramond ): void { - $pdf->Image($this->imgDir.'title.png', 126, 0, 600); - $pdf->Image($this->imgDir.'background.png', 280, 176, 291, 340); - $pdf->Image($this->imgDir.'signature.png', 140, 410, 90, 80); + $pdf->Image($this->imgDir . 'title.png', 126, 0, 600); + $pdf->Image($this->imgDir . 'background.png', 280, 176, 291, 340); + $pdf->Image($this->imgDir . 'signature.png', 140, 410, 90, 80); $pdf->SetFont('times', 'B', 24); $pdf->SetTextColor(0, 0, 0); @@ -136,7 +135,7 @@ class CertificatePdfService $pdf->SetFont('helvetica', '', 8); $pdf->SetTextColor(150, 150, 150); $pdf->SetXY(70.86, $H - 39.68); - $pdf->Cell(200, 12, 'Certificate No. '.$certNumber, 0, 0, 'L'); + $pdf->Cell(200, 12, 'Certificate No. ' . $certNumber, 0, 0, 'L'); $pdf->SetTextColor(0, 0, 0); } } @@ -162,7 +161,7 @@ class CertificatePdfService $lower = strtolower($clean); if (preg_match('/^\d+$/', $clean) && (int) $clean >= 1 && (int) $clean <= 9) { - return 'Grade '.$clean; + return 'Grade ' . $clean; } if ($lower === 'youth') { return 'Youth'; diff --git a/app/Services/ClassPreparation/ClassPreparationAdjustmentWriterService.php b/app/Services/ClassPreparation/ClassPreparationAdjustmentWriterService.php index 83d75c7e..fb2b0942 100644 --- a/app/Services/ClassPreparation/ClassPreparationAdjustmentWriterService.php +++ b/app/Services/ClassPreparation/ClassPreparationAdjustmentWriterService.php @@ -16,7 +16,7 @@ class ClassPreparationAdjustmentWriterService foreach ($adjustments as $itemName => $adjustment) { $item = (string) $itemName; - if ($item === '' || ! isset($allowed[$item])) { + if ($item === '' || !isset($allowed[$item])) { continue; } @@ -32,7 +32,6 @@ class ClassPreparationAdjustmentWriterService 'adjustable' => 1, ]); $count++; - continue; } diff --git a/app/Services/ClassPreparation/ClassPreparationCalculatorService.php b/app/Services/ClassPreparation/ClassPreparationCalculatorService.php index 96ff72dc..8b23c58e 100644 --- a/app/Services/ClassPreparation/ClassPreparationCalculatorService.php +++ b/app/Services/ClassPreparation/ClassPreparationCalculatorService.php @@ -37,7 +37,6 @@ class ClassPreparationCalculatorService if ($numValue > 0 && $numValue < 30) { $firstDigit = (int) substr((string) $numValue, 0, 1); - return $firstDigit === 1 ? 1 : ($firstDigit === 2 ? 2 : 3); } @@ -70,12 +69,10 @@ class ClassPreparationCalculatorService if ($gradeMin !== null && $classLevel < (int) $gradeMin) { $items[$name] = 0; - continue; } if ($gradeMax !== null && $classLevel > (int) $gradeMax) { $items[$name] = 0; - continue; } diff --git a/app/Services/ClassPreparation/ClassPreparationContextService.php b/app/Services/ClassPreparation/ClassPreparationContextService.php index 84591cdc..a3d80999 100644 --- a/app/Services/ClassPreparation/ClassPreparationContextService.php +++ b/app/Services/ClassPreparation/ClassPreparationContextService.php @@ -39,7 +39,6 @@ class ClassPreparationContextService ->count(); $this->rosterPresenceCache[$key] = $cnt > 0; - return $this->rosterPresenceCache[$key]; } } diff --git a/app/Services/ClassPreparation/ClassPreparationInventoryService.php b/app/Services/ClassPreparation/ClassPreparationInventoryService.php index 2f443429..c28c847a 100644 --- a/app/Services/ClassPreparation/ClassPreparationInventoryService.php +++ b/app/Services/ClassPreparation/ClassPreparationInventoryService.php @@ -50,7 +50,7 @@ class ClassPreparationInventoryService } $needsFallback = array_filter($inventoryMap, static fn ($v) => (int) $v === 0); - if (! empty($needsFallback)) { + if (!empty($needsFallback)) { $fallbackRows = DB::table('inventory_items') ->select('name AS item_name, COALESCE(SUM(CASE WHEN good_qty IS NOT NULL AND good_qty > 0 THEN good_qty WHEN `condition`=\"good\" THEN quantity ELSE quantity END),0) AS available') ->where('type', 'classroom') @@ -79,7 +79,6 @@ class ClassPreparationInventoryService if ($goodQty > 0) { $inventoryMap[$name] = $goodQty; - continue; } diff --git a/app/Services/ClassPreparation/ClassPreparationLogService.php b/app/Services/ClassPreparation/ClassPreparationLogService.php index 42ff6c25..23d51b96 100644 --- a/app/Services/ClassPreparation/ClassPreparationLogService.php +++ b/app/Services/ClassPreparation/ClassPreparationLogService.php @@ -33,7 +33,6 @@ class ClassPreparationLogService 'prep_data' => json_encode($items), 'created_at' => $createdAt, ]); - return true; } catch (\Throwable $e) { return false; diff --git a/app/Services/ClassPreparation/ClassPreparationPrintService.php b/app/Services/ClassPreparation/ClassPreparationPrintService.php index d1e06c45..ae9128f2 100644 --- a/app/Services/ClassPreparation/ClassPreparationPrintService.php +++ b/app/Services/ClassPreparation/ClassPreparationPrintService.php @@ -13,7 +13,8 @@ class ClassPreparationPrintService private ClassPreparationCalculatorService $calculator, private ClassPreparationAdjustmentService $adjustments, private ClassPreparationLogService $logs - ) {} + ) { + } public function printPrep(string $classSectionId, string $schoolYear, ?string $semester = null): array { @@ -30,7 +31,7 @@ class ClassPreparationPrintService $printedAt = $this->utcNow(); $ok = $this->logs->createLog($classSectionId, $className, $schoolYear, $items, $printedAt); - if (! $ok) { + if (!$ok) { Log::warning('Failed to store class preparation log.', [ 'class_section_id' => $classSectionId, 'school_year' => $schoolYear, @@ -54,7 +55,6 @@ class ClassPreparationPrintService if (function_exists('utc_now')) { return (string) utc_now(); } - return now('UTC')->toDateTimeString(); } } diff --git a/app/Services/ClassPreparation/ClassPreparationRosterService.php b/app/Services/ClassPreparation/ClassPreparationRosterService.php index 16c16a12..3332d00b 100644 --- a/app/Services/ClassPreparation/ClassPreparationRosterService.php +++ b/app/Services/ClassPreparation/ClassPreparationRosterService.php @@ -35,7 +35,6 @@ class ClassPreparationRosterService } $row = $query->first(); - return (int) ($row->cnt ?? 0); } } diff --git a/app/Services/ClassPreparation/ClassPreparationService.php b/app/Services/ClassPreparation/ClassPreparationService.php index 3a047a14..d24e210e 100644 --- a/app/Services/ClassPreparation/ClassPreparationService.php +++ b/app/Services/ClassPreparation/ClassPreparationService.php @@ -7,19 +7,12 @@ use App\Models\ClassSection; class ClassPreparationService { private ClassPreparationContextService $context; - private ClassPreparationRosterService $roster; - private ClassPreparationInventoryService $inventory; - private ClassPreparationCalculatorService $calculator; - private ClassPreparationAdjustmentService $adjustments; - private ClassPreparationLogService $logs; - private ClassPreparationAdjustmentWriterService $adjustmentWriter; - private ClassPreparationPrintService $printService; public function __construct( @@ -73,14 +66,14 @@ class ClassPreparationService $hasChanged = $this->logs->hasPrepChanged($baseItems, $oldPrep); $results[] = [ - 'class_section' => $className, + 'class_section' => $className, 'class_section_id' => $classSectionId, - 'student_count' => $studentCount, - 'class_level' => $classLevel, - 'prep_items' => $baseItems, - 'needs_print' => $hasChanged, - 'last_printed_at' => $oldSnap?->created_at, - 'adjustments' => $adjMap, + 'student_count' => $studentCount, + 'class_level' => $classLevel, + 'prep_items' => $baseItems, + 'needs_print' => $hasChanged, + 'last_printed_at' => $oldSnap?->created_at, + 'adjustments' => $adjMap, ]; } @@ -146,7 +139,6 @@ class ClassPreparationService if (function_exists('utc_now')) { return (string) utc_now(); } - return now('UTC')->toDateTimeString(); } } diff --git a/app/Services/ClassProgress/ClassProgressAttachmentService.php b/app/Services/ClassProgress/ClassProgressAttachmentService.php index bf849b42..b5b8559c 100644 --- a/app/Services/ClassProgress/ClassProgressAttachmentService.php +++ b/app/Services/ClassProgress/ClassProgressAttachmentService.php @@ -5,6 +5,7 @@ namespace App\Services\ClassProgress; use App\Models\ClassProgressAttachment; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Storage; class ClassProgressAttachmentService { @@ -16,7 +17,7 @@ class ClassProgressAttachmentService $stored = []; foreach ($files as $file) { - if (! $file instanceof UploadedFile || ! $file->isValid()) { + if (!$file instanceof UploadedFile || !$file->isValid()) { continue; } @@ -48,17 +49,17 @@ class ClassProgressAttachmentService $candidates = []; if (str_starts_with($path, 'storage/')) { $relative = ltrim(substr($path, strlen('storage/')), '/'); - $candidates[] = storage_path('app/public/'.$relative); + $candidates[] = storage_path('app/public/' . $relative); } if (str_starts_with($path, 'writable/uploads/')) { $relative = ltrim(substr($path, strlen('writable/uploads/')), '/'); - $candidates[] = storage_path('app/'.$relative); - $candidates[] = storage_path('app/public/'.$relative); + $candidates[] = storage_path('app/' . $relative); + $candidates[] = storage_path('app/public/' . $relative); } - $candidates[] = storage_path('app/'.ltrim($path, '/')); - $candidates[] = storage_path('app/public/'.ltrim($path, '/')); + $candidates[] = storage_path('app/' . ltrim($path, '/')); + $candidates[] = storage_path('app/public/' . ltrim($path, '/')); foreach ($candidates as $candidate) { if (is_file($candidate)) { @@ -83,6 +84,6 @@ class ClassProgressAttachmentService throw $e; } - return 'storage/'.ltrim($path, '/'); + return 'storage/' . ltrim($path, '/'); } } diff --git a/app/Services/ClassProgress/ClassProgressMetaService.php b/app/Services/ClassProgress/ClassProgressMetaService.php index bc04e930..8b016aeb 100644 --- a/app/Services/ClassProgress/ClassProgressMetaService.php +++ b/app/Services/ClassProgress/ClassProgressMetaService.php @@ -140,7 +140,7 @@ class ClassProgressMetaService public function curriculumOptions(?int $classId, ?string $schoolYear = null): array { - if (! $classId) { + if (!$classId) { return []; } diff --git a/app/Services/ClassProgress/ClassProgressMutationService.php b/app/Services/ClassProgress/ClassProgressMutationService.php index 7bcaf3e6..86602d0f 100644 --- a/app/Services/ClassProgress/ClassProgressMutationService.php +++ b/app/Services/ClassProgress/ClassProgressMutationService.php @@ -7,11 +7,10 @@ use App\Models\ClassProgressReport; use App\Models\TeacherClass; use App\Models\User; use App\Services\SchoolYears\SchoolYearContextService; -use Carbon\CarbonInterface; +use Illuminate\Support\Facades\Schema; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Facades\Schema; class ClassProgressMutationService { @@ -35,11 +34,11 @@ class ClassProgressMutationService $weekStart = (string) ($payload['week_start'] ?? ''); $weekEnd = $this->rules->ensureWeekEnd($weekStart, $payload['week_end'] ?? null); - if (! $this->rules->isWeekEndValid($weekStart, $weekEnd)) { + if (!$this->rules->isWeekEndValid($weekStart, $weekEnd)) { throw new \InvalidArgumentException('Week end must be the same as or after the week start.'); } - if (! $this->rules->hasIslamicUnitSelection($payload)) { + if (!$this->rules->hasIslamicUnitSelection($payload)) { throw new \InvalidArgumentException('Please select at least one Islamic Studies unit.'); } @@ -54,7 +53,7 @@ class ClassProgressMutationService ->values() ->all(); - if ($existingIds !== [] && ! $confirmOverwrite) { + if ($existingIds !== [] && !$confirmOverwrite) { throw new \InvalidArgumentException('CONFIRM_OVERWRITE'); } @@ -151,7 +150,7 @@ class ClassProgressMutationService throw new \InvalidArgumentException('Please select at least one Islamic Studies unit.'); } - $originalWeekStart = $anchor->week_start instanceof CarbonInterface + $originalWeekStart = $anchor->week_start instanceof \Carbon\CarbonInterface ? $anchor->week_start->format('Y-m-d') : (string) $anchor->week_start; @@ -296,7 +295,7 @@ class ClassProgressMutationService return DB::transaction(function () use ($report, $payload, $attachments) { $weekStart = $payload['week_start'] ?? $report->week_start?->format('Y-m-d'); $weekEnd = $this->rules->ensureWeekEnd((string) $weekStart, $payload['week_end'] ?? null); - if ($weekStart && $weekEnd && ! $this->rules->isWeekEndValid((string) $weekStart, (string) $weekEnd)) { + if ($weekStart && $weekEnd && !$this->rules->isWeekEndValid((string) $weekStart, (string) $weekEnd)) { throw new \InvalidArgumentException('Week end must be the same as or after the week start.'); } @@ -365,7 +364,7 @@ class ClassProgressMutationService ->where('class_section_id', $classSectionId) ->exists(); - if (! $assigned) { + if (!$assigned) { throw new \InvalidArgumentException('No class assignment found for this report.'); } } diff --git a/app/Services/ClassProgress/ClassProgressQueryService.php b/app/Services/ClassProgress/ClassProgressQueryService.php index 24c9ded0..c3d4aa50 100644 --- a/app/Services/ClassProgress/ClassProgressQueryService.php +++ b/app/Services/ClassProgress/ClassProgressQueryService.php @@ -8,8 +8,8 @@ use App\Models\Configuration; use App\Models\TeacherClass; use App\Models\User; use App\Services\SchoolYears\SchoolYearContextService; -use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Support\Facades\Schema; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; class ClassProgressQueryService { @@ -28,7 +28,7 @@ class ClassProgressQueryService ->with(['classSection', 'teacher']) ->orderBy($filters['sort_by'] ?? 'week_start', $filters['sort_dir'] ?? 'desc'); - if (! $this->isAdmin($user)) { + if (!$this->isAdmin($user)) { $relaxedSectionIds = TeacherClass::distinctSectionIdsForTeacher((int) $user->id); if (! empty($filters['class_section_id'])) { @@ -50,31 +50,31 @@ class ClassProgressQueryService $query->where('teacher_id', (int) $filters['teacher_id']); } - if (! empty($filters['class_section_id'])) { + if (!empty($filters['class_section_id'])) { $query->where('class_section_id', (int) $filters['class_section_id']); } - if (! empty($filters['subject'])) { + if (!empty($filters['subject'])) { $query->where('subject', (string) $filters['subject']); } - if (! empty($filters['status'])) { + if (!empty($filters['status'])) { $query->where('status', (string) $filters['status']); } - if (! empty($filters['school_year']) && Schema::hasColumn('class_progress_reports', 'school_year')) { + if (!empty($filters['school_year']) && Schema::hasColumn('class_progress_reports', 'school_year')) { $query->where('school_year', (string) $filters['school_year']); } - if (! empty($filters['semester']) && Schema::hasColumn('class_progress_reports', 'semester')) { + if (!empty($filters['semester']) && Schema::hasColumn('class_progress_reports', 'semester')) { $query->where('semester', (string) $filters['semester']); } - if (! empty($filters['week_start'])) { + if (!empty($filters['week_start'])) { $query->whereDate('week_start', '>=', $filters['week_start']); } - if (! empty($filters['week_end'])) { + if (!empty($filters['week_end'])) { $query->whereDate('week_end', '<=', $filters['week_end']); } @@ -114,7 +114,6 @@ class ClassProgressQueryService return $rows->map(function (ClassProgressReport $row) use ($attachments) { $row->setAttribute('status_label', $this->statusLabel($row->status)); $row->setAttribute('attachments', $attachments[$row->id] ?? []); - return $row; })->all(); } @@ -160,7 +159,6 @@ class ClassProgressQueryService private function statusLabel(?string $status): string { $options = (array) config('progress.status_options', []); - return $options[$status] ?? 'Unknown'; } diff --git a/app/Services/ClassProgress/ClassProgressRuleService.php b/app/Services/ClassProgress/ClassProgressRuleService.php index 3ca3c9ad..99e9c154 100644 --- a/app/Services/ClassProgress/ClassProgressRuleService.php +++ b/app/Services/ClassProgress/ClassProgressRuleService.php @@ -15,7 +15,6 @@ class ClassProgressRuleService public function normalizeFlags($flags): ?array { $values = array_values(array_filter((array) $flags, static fn ($item) => $item !== '' && $item !== null)); - return $values === [] ? null : $values; } @@ -81,7 +80,6 @@ class ClassProgressRuleService try { $dt = new \DateTime($weekStart); $dt->modify('+6 days'); - return $dt->format('Y-m-d'); } catch (\Exception $e) { return $weekStart; diff --git a/app/Services/ClassSections/ClassAttendanceService.php b/app/Services/ClassSections/ClassAttendanceService.php index 3b09af7b..46e28922 100644 --- a/app/Services/ClassSections/ClassAttendanceService.php +++ b/app/Services/ClassSections/ClassAttendanceService.php @@ -15,7 +15,7 @@ class ClassAttendanceService $semester = $semester ?: (string) (Configuration::getConfig('semester') ?? ''); $teacher = User::query()->find($teacherId); - $teacherName = trim((string) ($teacher?->firstname ?? '').' '.(string) ($teacher?->lastname ?? '')); + $teacherName = trim((string) ($teacher?->firstname ?? '') . ' ' . (string) ($teacher?->lastname ?? '')); $className = ClassSection::getClassSectionNameBySectionId($classSectionId) ?? (string) $classSectionId; $students = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, $teacherId); diff --git a/app/Services/ClassSections/ClassSectionQueryService.php b/app/Services/ClassSections/ClassSectionQueryService.php index 52e43933..1fc9e901 100644 --- a/app/Services/ClassSections/ClassSectionQueryService.php +++ b/app/Services/ClassSections/ClassSectionQueryService.php @@ -13,27 +13,27 @@ class ClassSectionQueryService ->leftJoin('classes', 'classSection.class_id', '=', 'classes.id') ->select('classSection.*', 'classes.class_name'); - if (! empty($filters['search'])) { - $term = '%'.strtolower((string) $filters['search']).'%'; + if (!empty($filters['search'])) { + $term = '%' . strtolower((string) $filters['search']) . '%'; $query->where(function ($q) use ($term) { $q->whereRaw('LOWER(classSection.class_section_name) LIKE ?', [$term]) ->orWhereRaw('LOWER(classes.class_name) LIKE ?', [$term]); }); } - if (! empty($filters['class_id'])) { + if (!empty($filters['class_id'])) { $query->where('classSection.class_id', (int) $filters['class_id']); } - if (! empty($filters['school_year'])) { + if (!empty($filters['school_year'])) { $query->where('classSection.school_year', (string) $filters['school_year']); } - if (! empty($filters['semester'])) { + if (!empty($filters['semester'])) { $query->where('classSection.semester', (string) $filters['semester']); } - if (! empty($filters['with_students'])) { + if (!empty($filters['with_students'])) { $query->whereExists(function ($sub) use ($filters) { $sub->selectRaw('1') ->from('student_class as sc') @@ -41,7 +41,7 @@ class ClassSectionQueryService ->whereColumn('sc.class_section_id', 'classSection.class_section_id') ->where('s.is_active', 1); - if (! empty($filters['school_year'])) { + if (!empty($filters['school_year'])) { $sub->where('sc.school_year', (string) $filters['school_year']); } }); diff --git a/app/Services/Communication/CommunicationFamilyService.php b/app/Services/Communication/CommunicationFamilyService.php index 18bec187..af849bb0 100644 --- a/app/Services/Communication/CommunicationFamilyService.php +++ b/app/Services/Communication/CommunicationFamilyService.php @@ -51,7 +51,7 @@ class CommunicationFamilyService } $names = array_map(static function ($row) { - return trim(($row['firstname'] ?? '').' '.($row['lastname'] ?? '')); + return trim(($row['firstname'] ?? '') . ' ' . ($row['lastname'] ?? '')); }, $rows); return implode(' & ', $names); diff --git a/app/Services/Communication/CommunicationLogService.php b/app/Services/Communication/CommunicationLogService.php index 4ff6f3a3..f6bca614 100644 --- a/app/Services/Communication/CommunicationLogService.php +++ b/app/Services/Communication/CommunicationLogService.php @@ -9,7 +9,7 @@ class CommunicationLogService { public function log(array $payload): void { - if (! Schema::hasTable('communication_logs')) { + if (!Schema::hasTable('communication_logs')) { return; } diff --git a/app/Services/Communication/CommunicationPreviewService.php b/app/Services/Communication/CommunicationPreviewService.php index f6838f58..0539b745 100644 --- a/app/Services/Communication/CommunicationPreviewService.php +++ b/app/Services/Communication/CommunicationPreviewService.php @@ -5,9 +5,7 @@ namespace App\Services\Communication; class CommunicationPreviewService { private CommunicationTemplateService $templates; - private CommunicationStudentService $students; - private CommunicationFamilyService $families; public function __construct( @@ -28,7 +26,7 @@ class CommunicationPreviewService string $teacherName ): array { $template = $this->templates->findTemplateByKey($templateKey); - if (! $template) { + if (!$template) { return [ 'ok' => false, 'status' => 404, @@ -37,7 +35,7 @@ class CommunicationPreviewService } $student = $this->students->getStudentBasic($studentId); - if (! $student) { + if (!$student) { return [ 'ok' => false, 'status' => 404, @@ -48,7 +46,7 @@ class CommunicationPreviewService $salutation = $this->families->guardianSalutation($familyId); $autoVars = [ - 'student_fullname' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')), + 'student_fullname' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')), 'student_grade' => $student['grade'] ?? '', 'parent_salutation' => $salutation, 'date' => $this->formatLocalDate('Y-m-d'), @@ -72,7 +70,6 @@ class CommunicationPreviewService { return (string) preg_replace_callback('/\\{\\{\\s*([a-zA-Z0-9_\\.]+)\\s*\\}\\}/', function ($m) use ($vars) { $key = $m[1]; - return htmlspecialchars((string) ($vars[$key] ?? ''), ENT_QUOTES, 'UTF-8'); }, $template); } @@ -82,7 +79,6 @@ class CommunicationPreviewService if (function_exists('local_date') && function_exists('utc_now')) { return (string) local_date(utc_now(), $format); } - return now()->format($format); } } diff --git a/app/Services/Communication/CommunicationSendService.php b/app/Services/Communication/CommunicationSendService.php index 9041e053..c045a9a8 100644 --- a/app/Services/Communication/CommunicationSendService.php +++ b/app/Services/Communication/CommunicationSendService.php @@ -7,7 +7,6 @@ use App\Services\EmailService; class CommunicationSendService { private EmailService $mailer; - private CommunicationLogService $logService; public function __construct(EmailService $mailer, CommunicationLogService $logService) @@ -62,7 +61,7 @@ class CommunicationSendService $sendOk = false; } - if (! $sendOk && $error === null) { + if (!$sendOk && $error === null) { $error = 'Mailer returned false'; } @@ -91,7 +90,6 @@ class CommunicationSendService private function normalizeEmails(array $values): array { $out = array_values(array_unique(array_filter(array_map('strval', $values)))); - return array_values(array_filter($out, static function ($email) { return $email !== ''; })); diff --git a/app/Services/Communication/CommunicationStudentService.php b/app/Services/Communication/CommunicationStudentService.php index 164d8e6e..00c59790 100644 --- a/app/Services/Communication/CommunicationStudentService.php +++ b/app/Services/Communication/CommunicationStudentService.php @@ -33,13 +33,13 @@ class CommunicationStudentService ->orderBy('sc.id', 'desc') ->first(); - if (! $row) { + if (!$row) { return null; } $row = (array) $row; $grade = $row['registration_grade'] ?? ''; - if (! $grade && ! empty($row['class_section_name'])) { + if (!$grade && !empty($row['class_section_name'])) { $grade = $row['class_section_name']; } diff --git a/app/Services/Communication/CommunicationTemplateService.php b/app/Services/Communication/CommunicationTemplateService.php index 7f1663f8..372c8da6 100644 --- a/app/Services/Communication/CommunicationTemplateService.php +++ b/app/Services/Communication/CommunicationTemplateService.php @@ -17,7 +17,6 @@ class CommunicationTemplateService ->get() ->map(function ($row) use ($keyColumn, $bodyColumn) { $row = (array) $row; - return [ 'template_key' => (string) ($row[$keyColumn] ?? ''), 'subject' => (string) ($row['subject'] ?? ''), @@ -36,7 +35,7 @@ class CommunicationTemplateService ->where('is_active', 1) ->first(); - if (! $row) { + if (!$row) { return null; } @@ -53,7 +52,6 @@ class CommunicationTemplateService { $keyColumn = Schema::hasColumn('email_templates', 'template_key') ? 'template_key' : 'code'; $bodyColumn = Schema::hasColumn('email_templates', 'body') ? 'body' : 'body_html'; - return [$keyColumn, $bodyColumn]; } } diff --git a/app/Services/CompetitionScores/CompetitionScoresQueryService.php b/app/Services/CompetitionScores/CompetitionScoresQueryService.php index 6cc18268..e59d0adf 100644 --- a/app/Services/CompetitionScores/CompetitionScoresQueryService.php +++ b/app/Services/CompetitionScores/CompetitionScoresQueryService.php @@ -42,7 +42,7 @@ class CompetitionScoresQueryService public function getQuestionCounts(array $competitionIds, int $classSectionId): array { - if (! $this->hasQuestionCount() || empty($competitionIds)) { + if (!$this->hasQuestionCount() || empty($competitionIds)) { return []; } @@ -93,7 +93,7 @@ class CompetitionScoresQueryService public function getQuestionCountForCompetition(int $competitionId, int $classSectionId): ?int { - if (! $this->hasQuestionCount()) { + if (!$this->hasQuestionCount()) { return null; } diff --git a/app/Services/CompetitionScores/CompetitionScoresRosterService.php b/app/Services/CompetitionScores/CompetitionScoresRosterService.php index 4c849c48..06727500 100644 --- a/app/Services/CompetitionScores/CompetitionScoresRosterService.php +++ b/app/Services/CompetitionScores/CompetitionScoresRosterService.php @@ -35,7 +35,6 @@ class CompetitionScoresRosterService } $row = (array) $builder->first(); - return (int) ($row['total'] ?? 0); } @@ -47,7 +46,7 @@ class CompetitionScoresRosterService $builder = DB::table('students as s') ->select('s.id', 's.school_id', 's.firstname', 's.lastname') - ->join($this->classStudentTable.' as cs', 'cs.student_id', '=', 's.id') + ->join($this->classStudentTable . ' as cs', 'cs.student_id', '=', 's.id') ->where('cs.class_section_id', $classSectionId); if (Schema::hasColumn($this->classStudentTable, 'school_year')) { diff --git a/app/Services/CompetitionScores/CompetitionScoresSaveService.php b/app/Services/CompetitionScores/CompetitionScoresSaveService.php index f27ed494..5d0bf68a 100644 --- a/app/Services/CompetitionScores/CompetitionScoresSaveService.php +++ b/app/Services/CompetitionScores/CompetitionScoresSaveService.php @@ -16,9 +16,8 @@ class CompetitionScoresSaveService if ($scoreValue === '') { continue; } - if (! preg_match('/^\\d+$/', $scoreValue)) { + if (!preg_match('/^\\d+$/', $scoreValue)) { $invalidScores[] = (int) $studentId; - continue; } $cleanScores[(int) $studentId] = (int) $scoreValue; diff --git a/app/Services/Dashboard/DashboardRouteService.php b/app/Services/Dashboard/DashboardRouteService.php index beba360c..e5074d16 100644 --- a/app/Services/Dashboard/DashboardRouteService.php +++ b/app/Services/Dashboard/DashboardRouteService.php @@ -12,9 +12,8 @@ class DashboardRouteService public function resolveForUser(?User $user): array { - if (! $user) { + if (!$user) { Log::warning('Dashboard route requested without an authenticated user.'); - return [ 'route' => self::FALLBACK_ROUTE, 'role' => null, @@ -49,7 +48,7 @@ class DashboardRouteService $rows = Role::findByNamesOrSlugs($lookupRoles); - if (! empty($rows)) { + if (!empty($rows)) { $role = $rows[0]; $route = $role->dashboard_route ?: self::FALLBACK_ROUTE; diff --git a/app/Services/Discounts/DiscountApplyService.php b/app/Services/Discounts/DiscountApplyService.php index 3917d6e9..08f7d9dd 100644 --- a/app/Services/Discounts/DiscountApplyService.php +++ b/app/Services/Discounts/DiscountApplyService.php @@ -10,7 +10,6 @@ use Illuminate\Support\Facades\Log; class DiscountApplyService { private DiscountContextService $context; - private DiscountInvoiceService $invoiceService; public function __construct(DiscountContextService $context, DiscountInvoiceService $invoiceService) @@ -25,7 +24,7 @@ class DiscountApplyService $semester = $this->context->getSemester(); $voucher = DiscountVoucher::query()->find($voucherId); - if (! $voucher) { + if (!$voucher) { return ['ok' => false, 'message' => 'Voucher not found.']; } @@ -44,7 +43,7 @@ class DiscountApplyService return ['ok' => false, 'message' => 'This voucher has reached its maximum allowed uses.']; } - if (! $allowAdditional) { + if (!$allowAdditional) { $rows = DB::table('discount_usages as du') ->select('i.parent_id') ->join('invoices as i', 'i.id', '=', 'du.invoice_id') @@ -56,7 +55,7 @@ class DiscountApplyService ->all(); $blockedParentIds = array_map(static fn ($r) => (int) ($r['parent_id'] ?? 0), $rows); - if (! empty($blockedParentIds)) { + if (!empty($blockedParentIds)) { $parentIds = array_values(array_diff(array_map('intval', $parentIds), $blockedParentIds)); } if (empty($parentIds)) { @@ -82,7 +81,6 @@ class DiscountApplyService 'parent_id' => (int) $parentId, 'voucher_id' => $voucherId, ]); - continue; } @@ -101,7 +99,7 @@ class DiscountApplyService continue; } - if (! $allowAdditional) { + if (!$allowAdditional) { $exists = DB::table('discount_usages as du') ->join('invoices as i', 'du.invoice_id', '=', 'i.id') ->where('du.voucher_id', $voucherId) @@ -199,7 +197,6 @@ class DiscountApplyService DB::commit(); } catch (\Throwable $e) { DB::rollBack(); - return ['ok' => false, 'message' => 'Voucher application failed. Transaction rolled back.']; } @@ -289,7 +286,7 @@ class DiscountApplyService event('paymentReceived', [$eventData, $studentData]); } } catch (\Throwable $e) { - Log::warning('paymentReceived hook failed: '.$e->getMessage()); + Log::warning('paymentReceived hook failed: ' . $e->getMessage()); } } } diff --git a/app/Services/Discounts/DiscountInvoiceService.php b/app/Services/Discounts/DiscountInvoiceService.php index d5c42a85..12bec3d5 100644 --- a/app/Services/Discounts/DiscountInvoiceService.php +++ b/app/Services/Discounts/DiscountInvoiceService.php @@ -17,12 +17,13 @@ class DiscountInvoiceService { public function __construct( private ApplicationUrlService $urls, - ) {} + ) { + } public function getCurrentInvoiceBalance(int $invoiceId, string $schoolYear): float { $invoice = Invoice::query()->find($invoiceId); - if (! $invoice) { + if (!$invoice) { return 0.0; } @@ -65,14 +66,13 @@ class DiscountInvoiceService $totalRefundPaid = (float) ($rowRefund['total_refund_paid'] ?? 0); $total = (float) ($invoice->total_amount ?? 0); - return max(0.0, round($total - $totalPaid - $totalDisc - $totalRefundPaid, 2)); } public function recalculateInvoice(int $invoiceId, string $schoolYear): void { $invoice = Invoice::query()->find($invoiceId); - if (! $invoice) { + if (!$invoice) { return; } @@ -118,7 +118,7 @@ class DiscountInvoiceService } $tuitionStudents = $registered; - if (! $refundAllowed) { + if (!$refundAllowed) { $tuitionStudents = array_merge($tuitionStudents, $withdrawn); } @@ -129,7 +129,7 @@ class DiscountInvoiceService foreach ($tuitionStudents as &$s) { $name = null; - if (! empty($s['class_section_id'])) { + if (!empty($s['class_section_id'])) { $name = ClassSection::getClassSectionNameBySectionId($s['class_section_id']); } $s['grade_name'] = is_string($name) ? strtoupper(trim($name)) : 'N/A'; @@ -236,13 +236,13 @@ class DiscountInvoiceService public function updateEnrollmentStatusIfPaid(int $invoiceId, string $schoolYear): int { $invoice = Invoice::query()->find($invoiceId); - if (! $invoice) { + if (!$invoice) { return 0; } $total = (float) ($invoice->total_amount ?? 0); $balance = (float) ($invoice->balance ?? 0); - if (! ($total > 0 && $balance < $total)) { + if (!($total > 0 && $balance < $total)) { return 0; } @@ -281,7 +281,7 @@ class DiscountInvoiceService ->orWhereRaw("LOWER(TRIM(REPLACE(enrollment_status, CHAR(160), ' '))) = 'payment pending'"); }); - if (! empty($paidEnrollmentIds)) { + if (!empty($paidEnrollmentIds)) { $query->whereIn('id', array_values(array_unique($paidEnrollmentIds))); } @@ -314,7 +314,7 @@ class DiscountInvoiceService string $semester ): array { $invoice = Invoice::query()->find($invoiceId); - if (! $invoice) { + if (!$invoice) { throw new \RuntimeException("Invoice {$invoiceId} not found"); } @@ -380,7 +380,6 @@ class DiscountInvoiceService if (preg_match('/^Y(?:OUTH)?\\s*(\\d+)?$/', $g, $m)) { $n = isset($m[1]) && $m[1] !== '' ? max(1, (int) $m[1]) : 1; - return $gradeFee + $n; } @@ -396,7 +395,6 @@ class DiscountInvoiceService if (function_exists('local_date') && function_exists('utc_now')) { return (string) local_date(utc_now(), $format); } - return now()->format($format); } } diff --git a/app/Services/Discounts/DiscountVoucherService.php b/app/Services/Discounts/DiscountVoucherService.php index d8f02426..068919f3 100644 --- a/app/Services/Discounts/DiscountVoucherService.php +++ b/app/Services/Discounts/DiscountVoucherService.php @@ -33,7 +33,6 @@ class DiscountVoucherService $voucher = DiscountVoucher::query()->findOrFail($id); $voucher->fill($payload); $voucher->save(); - return $voucher; } diff --git a/app/Services/Docs/ApiDocsService.php b/app/Services/Docs/ApiDocsService.php index 6055fa5c..425b8130 100644 --- a/app/Services/Docs/ApiDocsService.php +++ b/app/Services/Docs/ApiDocsService.php @@ -9,7 +9,8 @@ class ApiDocsService { public function __construct( private ApplicationUrlService $urls, - ) {} + ) { + } /** * Bootstrap payload for the documentation SPA (replaces legacy swagger_ui / swagger_ui_public views). diff --git a/app/Services/Docs/DocsCatalogService.php b/app/Services/Docs/DocsCatalogService.php index 17c1bcba..adc9265e 100644 --- a/app/Services/Docs/DocsCatalogService.php +++ b/app/Services/Docs/DocsCatalogService.php @@ -2,18 +2,18 @@ namespace App\Services\Docs; -use App\Controllers\DocsController; use App\Services\ApplicationUrlService; /** - * legacy parity: {@see DocsController::index} and + * legacy parity: {@see \App\Controllers\DocsController::index} and * {@see \App\Controllers\View\DocsController::swagger} (multi-spec Swagger UI payload). */ class DocsCatalogService { public function __construct( private ApplicationUrlService $urls, - ) {} + ) { + } /** * Hub metadata for the docs landing route (replaces Blade `docs/index`). diff --git a/app/Services/Docs/OpenApiRouteExporter.php b/app/Services/Docs/OpenApiRouteExporter.php index 3d2a0fba..82dec7ed 100644 --- a/app/Services/Docs/OpenApiRouteExporter.php +++ b/app/Services/Docs/OpenApiRouteExporter.php @@ -29,22 +29,22 @@ class OpenApiRouteExporter private function mergeRoute(array &$paths, Route $route): void { - if (! $this->isDocumentableRoute($route)) { + if (!$this->isDocumentableRoute($route)) { return; } $uriRaw = ltrim($route->uri(), '/'); if (str_starts_with($uriRaw, 'api/')) { - $uri = '/'.$uriRaw; + $uri = '/' . $uriRaw; } elseif (str_starts_with($uriRaw, 'v1/')) { - $uri = '/api/'.$uriRaw; + $uri = '/api/' . $uriRaw; } elseif ($uriRaw === 'v1') { $uri = '/api/v1'; } else { return; } - if (! str_starts_with($uri, '/api/v1')) { + if (!str_starts_with($uri, '/api/v1')) { return; } @@ -56,7 +56,7 @@ class OpenApiRouteExporter $tag = $this->resolveTag($uri); foreach ($methods as $method) { $lower = strtolower($method); - if (! isset($paths[$uri][$lower])) { + if (!isset($paths[$uri][$lower])) { $paths[$uri][$lower] = [ 'tags' => [$tag], 'summary' => $this->summaryFromAction($route), @@ -73,12 +73,12 @@ class OpenApiRouteExporter private function isDocumentableRoute(Route $route): bool { $uri = ltrim($route->uri(), '/'); - if (! str_starts_with($uri, 'api/v1') && ! str_starts_with($uri, 'v1/')) { + if (!str_starts_with($uri, 'api/v1') && !str_starts_with($uri, 'v1/')) { return false; } $action = $route->getActionName(); - if (! is_string($action)) { + if (!is_string($action)) { return false; } @@ -120,13 +120,11 @@ class OpenApiRouteExporter if (is_string($action) && str_contains($action, '@')) { [$controller, $method] = explode('@', $action, 2); $base = class_basename($controller); - - return $base.'::'.$method; + return $base . '::' . $method; } if (is_string($action)) { return $action; } - return 'Endpoint'; } } diff --git a/app/Services/Email/EmailAttachmentService.php b/app/Services/Email/EmailAttachmentService.php index a330d6da..7ba2c497 100644 --- a/app/Services/Email/EmailAttachmentService.php +++ b/app/Services/Email/EmailAttachmentService.php @@ -11,17 +11,17 @@ class EmailAttachmentService if ($files instanceof UploadedFile) { $files = [$files]; } - if (! is_array($files)) { + if (!is_array($files)) { return []; } $out = []; foreach ($files as $file) { - if (! $file instanceof UploadedFile || ! $file->isValid()) { + if (!$file instanceof UploadedFile || !$file->isValid()) { continue; } $path = $file->getRealPath(); - if (! $path || ! is_file($path)) { + if (!$path || !is_file($path)) { continue; } $out[] = [ diff --git a/app/Services/Email/EmailDispatchService.php b/app/Services/Email/EmailDispatchService.php index b65eb143..1a0b55b4 100644 --- a/app/Services/Email/EmailDispatchService.php +++ b/app/Services/Email/EmailDispatchService.php @@ -7,7 +7,9 @@ use PHPMailer\PHPMailer\PHPMailer; class EmailDispatchService { - public function __construct(private EmailProfileService $profiles) {} + public function __construct(private EmailProfileService $profiles) + { + } public function send( string $recipient, @@ -23,7 +25,6 @@ class EmailDispatchService if (empty($cfg['host']) || empty($cfg['user']) || $cfg['pass'] === '') { logger()->error("[mail:$profile] Missing SMTP config (host/user/pass). Check MAIL_{$this->profiles->envKeyFromProfile($profile)}_* or MAIL_DEFAULT_*/MAIL_*."); - return false; } @@ -60,7 +61,7 @@ class EmailDispatchService 'ssl' => [ 'verify_peer' => $verifyPeer, 'verify_peer_name' => $verifyPeer, - 'allow_self_signed' => ! $verifyPeer, + 'allow_self_signed' => !$verifyPeer, ], ]; @@ -68,17 +69,17 @@ class EmailDispatchService $mail->Debugoutput = 'error_log'; $mail->setFrom($cfg['fromEmail'], $cfg['fromName']); - if (! empty($cfg['returnPath'])) { + if (!empty($cfg['returnPath'])) { $mail->Sender = $cfg['returnPath']; } $mail->clearReplyTos(); $rtEmail = env('MAIL_DEFAULT_REPLY_TO'); $rtName = env('MAIL_DEFAULT_REPLY_TO_NAME'); - if (! $rtEmail || ! filter_var($rtEmail, FILTER_VALIDATE_EMAIL)) { + if (!$rtEmail || !filter_var($rtEmail, FILTER_VALIDATE_EMAIL)) { $rtEmail = $replyToEmail ?: ($cfg['replyTo'] ?: $cfg['fromEmail']); } - if (! $rtName) { + if (!$rtName) { $rtName = $replyToName ?: ($cfg['replyToName'] ?: $cfg['fromName']); } $rtName = $this->profiles->sanitizeReplyToName($rtName, $cfg['fromName']); @@ -86,7 +87,7 @@ class EmailDispatchService $mail->addReplyTo($rtEmail, $rtName); } - if (! empty($cfg['dkim']['domain']) && ! empty($cfg['dkim']['private']) && ! empty($cfg['dkim']['selector'])) { + if (!empty($cfg['dkim']['domain']) && !empty($cfg['dkim']['private']) && !empty($cfg['dkim']['selector'])) { $mail->DKIM_domain = $cfg['dkim']['domain']; $mail->DKIM_private = $cfg['dkim']['private']; $mail->DKIM_selector = $cfg['dkim']['selector']; @@ -96,7 +97,7 @@ class EmailDispatchService $mail->addAddress($recipient); foreach ($attachments as $att) { - if (! empty($att['path']) && is_file($att['path'])) { + if (!empty($att['path']) && is_file($att['path'])) { $mail->addAttachment($att['path'], $att['name'] ?? ''); } } @@ -110,17 +111,14 @@ class EmailDispatchService if ($ok) { logger()->info("[mail:$profile] Sent to {$recipient}, subj='{$subject}' via {$cfg['host']}:{$cfg['port']}/{$cfg['encryption']}"); - return true; } logger()->error("[mail:$profile] Failed: {$mail->ErrorInfo}. Debug: {$dbg}"); - return false; } catch (MailerException $e) { $dbg = $debugEnabled ? (ob_get_clean() ?: '') : ''; logger()->error("[mail:$profile] Exception: {$e->getMessage()} | PHPMailer: {$mail->ErrorInfo} | Debug: {$dbg}"); - return false; } } diff --git a/app/Services/Email/EmailExtractorService.php b/app/Services/Email/EmailExtractorService.php index 39924558..9219605e 100644 --- a/app/Services/Email/EmailExtractorService.php +++ b/app/Services/Email/EmailExtractorService.php @@ -57,7 +57,7 @@ class EmailExtractorService $needToAdd = []; foreach ($dbSet as $email => $_) { - if (! isset($csvSet[$email])) { + if (!isset($csvSet[$email])) { $needToAdd[] = $email; } } @@ -84,7 +84,6 @@ class EmailExtractorService $out[] = $email; } } - return array_values(array_unique($out)); } @@ -93,7 +92,6 @@ class EmailExtractorService $pattern = '/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i'; preg_match_all($pattern, $text, $matches); $emails = $matches[0] ?? []; - return $this->normalizeEmailArray($emails); } } diff --git a/app/Services/Email/EmailProfileService.php b/app/Services/Email/EmailProfileService.php index fa6638ee..14b76eab 100644 --- a/app/Services/Email/EmailProfileService.php +++ b/app/Services/Email/EmailProfileService.php @@ -37,7 +37,6 @@ class EmailProfileService return $v; } } - return $default; }; @@ -91,7 +90,6 @@ class EmailProfileService if ($trimmed === '' || preg_match('/^no[- ]?repl(?:y|ay)$/i', $trimmed)) { return $fallback; } - return $trimmed; } } diff --git a/app/Services/Email/EmailSenderOptionsService.php b/app/Services/Email/EmailSenderOptionsService.php index 3f1a0324..de6e4990 100644 --- a/app/Services/Email/EmailSenderOptionsService.php +++ b/app/Services/Email/EmailSenderOptionsService.php @@ -9,7 +9,7 @@ class EmailSenderOptionsService $json = env('MAIL_SENDERS', '{}'); $arr = json_decode($json, true); - if (! is_array($arr) || empty($arr)) { + if (!is_array($arr) || empty($arr)) { $smtpUser = getenv('SMTP_USER') ?: ''; $name = 'Al Rahma Sunday School'; @@ -17,7 +17,7 @@ class EmailSenderOptionsService 'key' => 'general', 'name' => $name, 'email' => $smtpUser, - 'label' => trim($name.($smtpUser ? " <{$smtpUser}>" : '')), + 'label' => trim($name . ($smtpUser ? " <{$smtpUser}>" : '')), ]]; } @@ -29,7 +29,7 @@ class EmailSenderOptionsService 'key' => (string) $key, 'name' => (string) $name, 'email' => (string) $email, - 'label' => trim($name.($email ? " <{$email}>" : '')), + 'label' => trim($name . ($email ? " <{$email}>" : '')), ]; } diff --git a/app/Services/EmailService.php b/app/Services/EmailService.php index 81cbd8a2..6acf3238 100644 --- a/app/Services/EmailService.php +++ b/app/Services/EmailService.php @@ -14,7 +14,8 @@ class EmailService string $fromKey = 'general', array $cc = [], array $bcc = [] - ): bool { + ): bool + { $sender = $this->resolveSender($fromKey); try { @@ -23,18 +24,16 @@ class EmailService if ($sender['email'] !== '') { $message->from($sender['email'], $sender['name']); } - if (! empty($cc)) { + if (!empty($cc)) { $message->cc($cc); } - if (! empty($bcc)) { + if (!empty($bcc)) { $message->bcc($bcc); } }); - return true; } catch (\Throwable $e) { - Log::error('EmailService send failed: '.$e->getMessage()); - + Log::error('EmailService send failed: ' . $e->getMessage()); return false; } } @@ -47,7 +46,6 @@ class EmailService if (is_array($senders) && isset($senders[$fromKey])) { $info = $senders[$fromKey]; - return [ 'name' => (string) ($info['name'] ?? 'Sender'), 'email' => (string) ($info['email'] ?? ''), diff --git a/app/Services/EmergencyContacts/EmergencyContactCrudService.php b/app/Services/EmergencyContacts/EmergencyContactCrudService.php index 2a40c62e..044749e6 100644 --- a/app/Services/EmergencyContacts/EmergencyContactCrudService.php +++ b/app/Services/EmergencyContacts/EmergencyContactCrudService.php @@ -9,7 +9,8 @@ class EmergencyContactCrudService { public function __construct( private PhoneFormatterService $phoneFormatter - ) {} + ) { + } public function findForParent(int $contactId, int $parentId): array { diff --git a/app/Services/EmergencyContacts/EmergencyContactDirectoryService.php b/app/Services/EmergencyContacts/EmergencyContactDirectoryService.php index 666f0012..89d8c706 100644 --- a/app/Services/EmergencyContacts/EmergencyContactDirectoryService.php +++ b/app/Services/EmergencyContacts/EmergencyContactDirectoryService.php @@ -13,7 +13,7 @@ class EmergencyContactDirectoryService { public function groups(?array $parentIds = null): array { - $parentIds = ! empty($parentIds) + $parentIds = !empty($parentIds) ? array_values(array_filter(array_map('intval', $parentIds), static fn ($id) => $id > 0)) : EmergencyContact::query() ->distinct() @@ -28,7 +28,7 @@ class EmergencyContactDirectoryService $parent = User::query()->find($parentId); $parentName = $parent - ? trim((string) $parent->firstname.' '.(string) $parent->lastname) + ? trim((string) $parent->firstname . ' ' . (string) $parent->lastname) : 'Unknown Parent'; if ($parentName === '') { $parentName = 'Unknown Parent'; @@ -67,11 +67,11 @@ class EmergencyContactDirectoryService private function secondParentPhone(int $parentId): string { try { - if (! Schema::hasTable('parents')) { + if (!Schema::hasTable('parents')) { return ''; } - if (! Schema::hasColumn('parents', 'secondparent_phone')) { + if (!Schema::hasColumn('parents', 'secondparent_phone')) { return ''; } @@ -82,8 +82,7 @@ class EmergencyContactDirectoryService return $phone ? (string) $phone : ''; } catch (\Throwable $e) { - Log::debug('EmergencyContactDirectoryService: could not load second parent phone: '.$e->getMessage()); - + Log::debug('EmergencyContactDirectoryService: could not load second parent phone: ' . $e->getMessage()); return ''; } } diff --git a/app/Services/Events/EventChargeQueryService.php b/app/Services/Events/EventChargeQueryService.php index 1a973208..754d6854 100644 --- a/app/Services/Events/EventChargeQueryService.php +++ b/app/Services/Events/EventChargeQueryService.php @@ -4,6 +4,7 @@ namespace App\Services\Events; use App\Models\EventCharges; use Illuminate\Contracts\Pagination\LengthAwarePaginator; +use Illuminate\Support\Facades\DB; class EventChargeQueryService { @@ -25,16 +26,16 @@ class EventChargeQueryService ->leftJoin('students', 'students.id', '=', 'event_charges.student_id') ->leftJoin('events', 'events.id', '=', 'event_charges.event_id'); - if (! empty($filters['school_year'])) { + if (!empty($filters['school_year'])) { $query->where('event_charges.school_year', (string) $filters['school_year']); } - if (! empty($filters['semester'])) { + if (!empty($filters['semester'])) { $query->where('event_charges.semester', (string) $filters['semester']); } - if (! empty($filters['parent_id'])) { + if (!empty($filters['parent_id'])) { $query->where('event_charges.parent_id', (int) $filters['parent_id']); } - if (! empty($filters['event_id'])) { + if (!empty($filters['event_id'])) { $query->where('event_charges.event_id', (int) $filters['event_id']); } diff --git a/app/Services/Events/EventChargeService.php b/app/Services/Events/EventChargeService.php index d9f1370d..cac21166 100644 --- a/app/Services/Events/EventChargeService.php +++ b/app/Services/Events/EventChargeService.php @@ -9,7 +9,9 @@ use App\Services\Invoices\InvoiceGenerationService; class EventChargeService { - public function __construct(private InvoiceGenerationService $invoiceGeneration) {} + public function __construct(private InvoiceGenerationService $invoiceGeneration) + { + } public function seedChargesForEvent(Event $event, string $schoolYear, string $semester, float $amount, int $actorId): array { @@ -80,7 +82,7 @@ class EventChargeService int $actorId ): array { $event = Event::getEvent($eventId, $schoolYear); - if (! $event) { + if (!$event) { return ['ok' => false, 'message' => 'Event not found.']; } @@ -107,7 +109,6 @@ class EventChargeService $existing->delete(); $deleted++; } - continue; } diff --git a/app/Services/Events/EventListService.php b/app/Services/Events/EventListService.php index 996e3590..cd2283c9 100644 --- a/app/Services/Events/EventListService.php +++ b/app/Services/Events/EventListService.php @@ -16,19 +16,19 @@ class EventListService $activeOnly = $filters['active'] ?? null; $allowedSorts = ['created_at', 'expiration_date', 'event_name']; - if (! in_array($sortBy, $allowedSorts, true)) { + if (!in_array($sortBy, $allowedSorts, true)) { $sortBy = 'created_at'; } $query = Event::query(); - if (! empty($filters['school_year'])) { + if (!empty($filters['school_year'])) { $query->where('school_year', (string) $filters['school_year']); } - if (! empty($filters['semester'])) { + if (!empty($filters['semester'])) { $query->where('semester', (string) $filters['semester']); } - if (! empty($filters['q'])) { + if (!empty($filters['q'])) { $term = trim((string) $filters['q']); $query->where('event_name', 'like', "%{$term}%"); } @@ -67,10 +67,10 @@ class EventListService private function activeCount(array $filters): int { $query = Event::query()->whereDate('expiration_date', '>=', now()->toDateString()); - if (! empty($filters['school_year'])) { + if (!empty($filters['school_year'])) { $query->where('school_year', (string) $filters['school_year']); } - if (! empty($filters['semester'])) { + if (!empty($filters['semester'])) { $query->where('semester', (string) $filters['semester']); } diff --git a/app/Services/Events/EventManagementService.php b/app/Services/Events/EventManagementService.php index aa1fcd41..ac327586 100644 --- a/app/Services/Events/EventManagementService.php +++ b/app/Services/Events/EventManagementService.php @@ -13,7 +13,8 @@ class EventManagementService public function __construct( private EventChargeService $charges, private InvoiceGenerationService $invoiceGeneration - ) {} + ) { + } public function create(array $payload, ?UploadedFile $flyer, int $actorId): array { @@ -53,7 +54,7 @@ class EventManagementService public function update(int $eventId, array $payload, ?UploadedFile $flyer): array { $event = Event::query()->find($eventId); - if (! $event) { + if (!$event) { return ['ok' => false, 'message' => 'Event not found.']; } @@ -80,7 +81,7 @@ class EventManagementService public function delete(int $eventId, int $actorId): array { $event = Event::query()->find($eventId); - if (! $event) { + if (!$event) { return ['ok' => false, 'message' => 'Event not found.']; } @@ -98,7 +99,7 @@ class EventManagementService private function storeFlyer(?UploadedFile $file): ?string { - if (! $file || ! $file->isValid()) { + if (!$file || !$file->isValid()) { return null; } @@ -119,13 +120,13 @@ class EventManagementService } $dir = public_path('uploads/event_flyers'); - if (! File::exists($dir)) { + if (!File::exists($dir)) { File::makeDirectory($dir, 0755, true); } - $name = bin2hex(random_bytes(16)).'.'.$allowed[$mime]; + $name = bin2hex(random_bytes(16)) . '.' . $allowed[$mime]; $file->move($dir, $name); - return 'event_flyers/'.$name; + return 'event_flyers/' . $name; } } diff --git a/app/Services/Events/EventStudentChargeService.php b/app/Services/Events/EventStudentChargeService.php index c3d8790d..26a2ca6c 100644 --- a/app/Services/Events/EventStudentChargeService.php +++ b/app/Services/Events/EventStudentChargeService.php @@ -30,7 +30,7 @@ class EventStudentChargeService foreach ($students as $student) { $data[] = [ 'id' => (int) ($student['id'] ?? 0), - 'name' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')), + 'name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')), 'charged' => isset($chargedMap[(int) ($student['id'] ?? 0)]), ]; } diff --git a/app/Services/Exams/ExamDraftAdminService.php b/app/Services/Exams/ExamDraftAdminService.php index 13dff9ae..9f22c66a 100644 --- a/app/Services/Exams/ExamDraftAdminService.php +++ b/app/Services/Exams/ExamDraftAdminService.php @@ -4,7 +4,6 @@ namespace App\Services\Exams; use App\Models\ClassSection; use App\Models\ExamDraft; -use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\DB; class ExamDraftAdminService @@ -12,7 +11,8 @@ class ExamDraftAdminService public function __construct( private ExamDraftConfigService $configService, private ExamDraftFileService $fileService - ) {} + ) { + } public function list(): array { @@ -29,7 +29,7 @@ class ExamDraftAdminService if ($teacherUserColumn !== '') { $draftsQuery - ->leftJoin('users as u', 'u.id', '=', "ed.{$teacherUserColumn}") + ->leftJoin('users as u', "u.id", '=', "ed.{$teacherUserColumn}") ->addSelect( 'u.firstname as teacher_first', 'u.lastname as teacher_last' @@ -82,15 +82,15 @@ class ExamDraftAdminService $legacyByClass = []; if ($context['has_legacy'] ?? false) { foreach ($drafts as $row) { - $isLegacy = ! empty($row['is_legacy']); - if (! $isLegacy) { + $isLegacy = !empty($row['is_legacy']); + if (!$isLegacy) { continue; } $cid = (int) ($row['class_section_id'] ?? 0); - if (! isset($legacyByClass[$cid])) { + if (!isset($legacyByClass[$cid])) { $legacyByClass[$cid] = [ 'class_section_id' => $cid, - 'class_section_name' => $row['class_section_name'] ?? 'Class '.$cid, + 'class_section_name' => $row['class_section_name'] ?? 'Class ' . $cid, 'items' => [], ]; } @@ -111,7 +111,7 @@ class ExamDraftAdminService ]; } - public function uploadLegacy(int $adminId, array $payload, UploadedFile $file): array + public function uploadLegacy(int $adminId, array $payload, \Illuminate\Http\UploadedFile $file): array { $context = $this->configService->context(); $adminUserColumn = (string) ($context['admin_user_column'] ?? ''); @@ -148,7 +148,7 @@ class ExamDraftAdminService $finalFilename = $stored['extension'] === 'pdf' ? $stored['original'] - : (pathinfo($stored['original'], PATHINFO_FILENAME).'.pdf'); + : (pathinfo($stored['original'], PATHINFO_FILENAME) . '.pdf'); $payload = [ 'class_section_id' => $classSectionId, @@ -193,7 +193,7 @@ class ExamDraftAdminService return ['ok' => true, 'draft' => $draft->toArray()]; } - public function review(int $adminId, array $payload, ?UploadedFile $file): array + public function review(int $adminId, array $payload, ?\Illuminate\Http\UploadedFile $file): array { $draftId = (int) ($payload['draft_id'] ?? 0); if ($draftId <= 0) { @@ -201,7 +201,7 @@ class ExamDraftAdminService } $draft = ExamDraft::query()->find($draftId); - if (! $draft) { + if (!$draft) { return ['ok' => false, 'message' => 'Submission not found.']; } @@ -209,7 +209,7 @@ class ExamDraftAdminService $statusInput = trim((string) ($payload['review_status'] ?? '')); $currentStatus = (string) ($draft->status ?? 'draft'); $status = $this->normalizeStatus($statusInput !== '' ? $statusInput : $currentStatus, $currentStatus); - if (! in_array($status, ExamDraftConfigService::STATUS_OPTIONS, true)) { + if (!in_array($status, ExamDraftConfigService::STATUS_OPTIONS, true)) { $status = 'reviewed'; } @@ -255,7 +255,7 @@ class ExamDraftAdminService if ($pdfName !== null && ($this->configService->context()['has_final_pdf'] ?? false)) { $update['final_pdf_file'] = $pdfName; } - } elseif ($status === 'finalized' && ! empty($draft->teacher_file ?: $draft->author_file)) { + } elseif ($status === 'finalized' && !empty($draft->teacher_file ?: $draft->author_file)) { $copied = $this->fileService->copyDraftToFinal( (string) ($draft->teacher_file ?? $draft->author_file), ExamDraftConfigService::TEACHER_UPLOAD_DIR, @@ -297,7 +297,6 @@ class ExamDraftAdminService if (isset($aliases[$input])) { $input = $aliases[$input]; } - return in_array($input, ExamDraftConfigService::STATUS_OPTIONS, true) ? $input : $default; } } diff --git a/app/Services/Exams/ExamDraftConfigService.php b/app/Services/Exams/ExamDraftConfigService.php index 3bfcbdf8..b7d0f68e 100644 --- a/app/Services/Exams/ExamDraftConfigService.php +++ b/app/Services/Exams/ExamDraftConfigService.php @@ -8,13 +8,9 @@ use Illuminate\Support\Facades\Schema; class ExamDraftConfigService { public const TEACHER_UPLOAD_DIR = 'exams/drafts'; - public const FINAL_UPLOAD_DIR = 'exams/finals'; - public const MAX_UPLOAD_BYTES = 12 * 1024 * 1024; - public const ALLOWED_EXTENSIONS = ['doc', 'docx']; - public const ADMIN_ALLOWED_EXTENSIONS = ['doc', 'docx', 'pdf']; public const EXAM_TYPES = [ diff --git a/app/Services/Exams/ExamDraftFileService.php b/app/Services/Exams/ExamDraftFileService.php index b880103e..d75a74e9 100644 --- a/app/Services/Exams/ExamDraftFileService.php +++ b/app/Services/Exams/ExamDraftFileService.php @@ -9,22 +9,21 @@ class ExamDraftFileService public function storeUploadedFile(UploadedFile $file, string $subdir, array $allowedExtensions, int $maxBytes): ?array { $ext = strtolower($file->getClientOriginalExtension()); - if (! in_array($ext, $allowedExtensions, true)) { + if (!in_array($ext, $allowedExtensions, true)) { return null; } if ($file->getSize() > $maxBytes) { return null; } - $destination = storage_path('uploads/'.trim($subdir, '/')); - if (! is_dir($destination)) { + $destination = storage_path('uploads/' . trim($subdir, '/')); + if (!is_dir($destination)) { mkdir($destination, 0755, true); } - $filename = uniqid('exam_', true).'.'.$ext; + $filename = uniqid('exam_', true) . '.' . $ext; try { $file->move($destination, $filename); - return [ 'stored' => $filename, 'original' => $file->getClientOriginalName(), @@ -44,49 +43,46 @@ class ExamDraftFileService $ext = strtolower((string) $originalExt); if ($ext === 'pdf') { $path = $this->fullUploadPath($subdir, $finalFilename); - return is_file($path) ? $finalFilename : null; } - return $this->convertDocToPdf($this->fullUploadPath($subdir, $finalFilename), $subdir); } public function copyDraftToFinal(string $draftFilename, string $sourceDir, string $targetDir): ?string { $source = $this->fullUploadPath($sourceDir, $draftFilename); - if (! is_file($source)) { + if (!is_file($source)) { return null; } - $destinationDir = storage_path('uploads/'.trim($targetDir, '/')); - if (! is_dir($destinationDir)) { + $destinationDir = storage_path('uploads/' . trim($targetDir, '/')); + if (!is_dir($destinationDir)) { mkdir($destinationDir, 0755, true); } $ext = pathinfo($draftFilename, PATHINFO_EXTENSION); - $destName = uniqid('final_', true).'.'.$ext; - $destPath = $destinationDir.'/'.$destName; - if (! @copy($source, $destPath)) { + $destName = uniqid('final_', true) . '.' . $ext; + $destPath = $destinationDir . '/' . $destName; + if (!@copy($source, $destPath)) { return null; } - return $destName; } private function convertDocToPdf(string $sourcePath, string $targetSubdir): ?string { $ext = strtolower(pathinfo($sourcePath, PATHINFO_EXTENSION)); - if (! in_array($ext, ['doc', 'docx'], true)) { + if (!in_array($ext, ['doc', 'docx'], true)) { return null; } - $targetDir = storage_path('uploads/'.trim($targetSubdir, '/')); - if (! is_dir($targetDir)) { + $targetDir = storage_path('uploads/' . trim($targetSubdir, '/')); + if (!is_dir($targetDir)) { mkdir($targetDir, 0755, true); } $base = pathinfo($sourcePath, PATHINFO_FILENAME); - $targetPath = $targetDir.'/'.$base.'.pdf'; + $targetPath = $targetDir . '/' . $base . '.pdf'; - $cmd = 'soffice --headless --convert-to pdf --outdir '.escapeshellarg($targetDir).' '.escapeshellarg($sourcePath).' 2>/dev/null'; + $cmd = 'soffice --headless --convert-to pdf --outdir ' . escapeshellarg($targetDir) . ' ' . escapeshellarg($sourcePath) . ' 2>/dev/null'; @exec($cmd); return is_file($targetPath) ? basename($targetPath) : null; @@ -100,13 +96,12 @@ class ExamDraftFileService $path = $this->fullUploadPath($subdir, $filename); $base = pathinfo($path, PATHINFO_FILENAME); $dir = pathinfo($path, PATHINFO_DIRNAME); - $pdfPath = $dir.'/'.$base.'.pdf'; - + $pdfPath = $dir . '/' . $base . '.pdf'; return is_file($pdfPath) ? basename($pdfPath) : null; } private function fullUploadPath(string $subdir, string $filename): string { - return storage_path('uploads/'.trim($subdir, '/').'/'.$filename); + return storage_path('uploads/' . trim($subdir, '/') . '/' . $filename); } } diff --git a/app/Services/Exams/ExamDraftTeacherService.php b/app/Services/Exams/ExamDraftTeacherService.php index d099d67b..fa28bdf7 100644 --- a/app/Services/Exams/ExamDraftTeacherService.php +++ b/app/Services/Exams/ExamDraftTeacherService.php @@ -4,7 +4,6 @@ namespace App\Services\Exams; use App\Models\ExamDraft; use App\Models\TeacherClass; -use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\DB; class ExamDraftTeacherService @@ -12,7 +11,8 @@ class ExamDraftTeacherService public function __construct( private ExamDraftConfigService $configService, private ExamDraftFileService $fileService - ) {} + ) { + } public function listForTeacher(int $teacherId): array { @@ -33,7 +33,7 @@ class ExamDraftTeacherService } $legacyExams = []; - if (($context['has_legacy'] ?? false) && ! empty($classSectionIds)) { + if (($context['has_legacy'] ?? false) && !empty($classSectionIds)) { $legacyExams = DB::table('exam_drafts as ed') ->select('ed.*', 'cs.class_section_name') ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'ed.class_section_id') @@ -58,7 +58,7 @@ class ExamDraftTeacherService ]; } - public function store(int $teacherId, array $payload, ?UploadedFile $file): array + public function store(int $teacherId, array $payload, ?\Illuminate\Http\UploadedFile $file): array { $context = $this->configService->context(); $schoolYear = (string) ($context['school_year'] ?? ''); @@ -77,7 +77,7 @@ class ExamDraftTeacherService ->where('class_section_id', $classSectionId) ->first(); - if (! $assignment) { + if (!$assignment) { return ['ok' => false, 'message' => 'You are not assigned to the selected class section.']; } diff --git a/app/Services/Expenses/ExpenseReceiptService.php b/app/Services/Expenses/ExpenseReceiptService.php index f748bcdf..e0720a5c 100644 --- a/app/Services/Expenses/ExpenseReceiptService.php +++ b/app/Services/Expenses/ExpenseReceiptService.php @@ -9,7 +9,8 @@ class ExpenseReceiptService { public function __construct( private ApplicationUrlService $urls - ) {} + ) { + } public function storeReceipt(UploadedFile $file): string { @@ -33,7 +34,7 @@ class ExpenseReceiptService throw new \InvalidArgumentException('Receipt file too large. Max 5MB.'); } - $filename = bin2hex(random_bytes(16)).'.'.$allowed[$mime]; + $filename = bin2hex(random_bytes(16)) . '.' . $allowed[$mime]; $file->storeAs('receipts', $filename); return $filename; diff --git a/app/Services/Expenses/ExpenseStaffService.php b/app/Services/Expenses/ExpenseStaffService.php index 16fb4a30..0a204b67 100644 --- a/app/Services/Expenses/ExpenseStaffService.php +++ b/app/Services/Expenses/ExpenseStaffService.php @@ -26,7 +26,7 @@ class ExpenseStaffService if ($id <= 0 || in_array($roleName, $excludedRoles, true)) { continue; } - if (! isset($staff[$id])) { + if (!isset($staff[$id])) { $staff[$id] = [ 'id' => $id, 'firstname' => $row['firstname'] ?? '', @@ -36,9 +36,8 @@ class ExpenseStaffService } uasort($staff, static function ($a, $b) { - $nameA = trim(($a['firstname'] ?? '').' '.($a['lastname'] ?? '')); - $nameB = trim(($b['firstname'] ?? '').' '.($b['lastname'] ?? '')); - + $nameA = trim(($a['firstname'] ?? '') . ' ' . ($a['lastname'] ?? '')); + $nameB = trim(($b['firstname'] ?? '') . ' ' . ($b['lastname'] ?? '')); return strcasecmp($nameA, $nameB); }); diff --git a/app/Services/Expenses/ExpenseWriteService.php b/app/Services/Expenses/ExpenseWriteService.php index a35d8eec..0bea865d 100644 --- a/app/Services/Expenses/ExpenseWriteService.php +++ b/app/Services/Expenses/ExpenseWriteService.php @@ -36,7 +36,6 @@ class ExpenseWriteService { $expense->fill($payload); $expense->save(); - return $expense; } } diff --git a/app/Services/ExtraCharges/ExtraChargesChargeService.php b/app/Services/ExtraCharges/ExtraChargesChargeService.php index af1e25bf..2bf33682 100644 --- a/app/Services/ExtraCharges/ExtraChargesChargeService.php +++ b/app/Services/ExtraCharges/ExtraChargesChargeService.php @@ -58,8 +58,7 @@ class ExtraChargesChargeService DB::commit(); } catch (\Throwable $e) { DB::rollBack(); - Log::error('Extra charge create failed: '.$e->getMessage()); - + Log::error('Extra charge create failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to save charge.']; } @@ -94,17 +93,15 @@ class ExtraChargesChargeService } $charge->save(); - if ($charge->status === 'applied' && ! empty($charge->invoice_id) && abs($delta) > 0.00001) { + if ($charge->status === 'applied' && !empty($charge->invoice_id) && abs($delta) > 0.00001) { $this->invoiceService->adjustDelta((int) $charge->invoice_id, $delta); } DB::commit(); - return true; } catch (\Throwable $e) { DB::rollBack(); - Log::error('Extra charge update failed: '.$e->getMessage()); - + Log::error('Extra charge update failed: ' . $e->getMessage()); return false; } } @@ -127,12 +124,10 @@ class ExtraChargesChargeService $charge->save(); DB::commit(); - return true; } catch (\Throwable $e) { DB::rollBack(); - Log::error('Extra charge void failed: '.$e->getMessage()); - + Log::error('Extra charge void failed: ' . $e->getMessage()); return false; } } @@ -158,25 +153,23 @@ class ExtraChargesChargeService $charge->save(); DB::commit(); - return true; } catch (\Throwable $e) { DB::rollBack(); - Log::error('Extra charge reverse failed: '.$e->getMessage()); - + Log::error('Extra charge reverse failed: ' . $e->getMessage()); return false; } } private function triggerExtraChargeEvent(?array $parentUser, array $payload, int $chargeId, ?int $invoiceId, array $invoiceBefore, array $invoiceAfter): void { - if (! $parentUser) { + if (!$parentUser) { return; } $first = $parentUser['first_name'] ?? $parentUser['firstname'] ?? ''; $last = $parentUser['last_name'] ?? $parentUser['lastname'] ?? ''; - $parentName = trim($first.' '.$last); + $parentName = trim($first . ' ' . $last); $before = $this->normalizeRow($invoiceBefore); $after = $this->normalizeRow($invoiceAfter); @@ -194,7 +187,7 @@ class ExtraChargesChargeService 'school_year' => $payload['school_year'], 'semester' => $payload['semester'], 'invoice_id' => $invoiceId, - 'invoice_number' => $after['invoice_number'] ?? ($invoiceId ? 'INV-'.$invoiceId : null), + 'invoice_number' => $after['invoice_number'] ?? ($invoiceId ? 'INV-' . $invoiceId : null), 'charge_id' => $chargeId, 'charge_title' => $payload['title'], 'charge_desc' => $payload['description'], @@ -219,19 +212,18 @@ class ExtraChargesChargeService event('extraCharge', [$eventData, $students]); } } catch (\Throwable $e) { - Log::warning('extraCharge event failed: '.$e->getMessage()); + Log::warning('extraCharge event failed: ' . $e->getMessage()); } } private function normalizeRow($row): ?array { - if (! $row) { + if (!$row) { return null; } if (is_array($row) && isset($row[0]) && is_array($row[0])) { return $row[0]; } - return is_array($row) ? $row : null; } @@ -240,7 +232,6 @@ class ExtraChargesChargeService if (function_exists('utc_now')) { return (string) utc_now(); } - return now('UTC')->toDateTimeString(); } } diff --git a/app/Services/ExtraCharges/ExtraChargesInvoiceService.php b/app/Services/ExtraCharges/ExtraChargesInvoiceService.php index 11465f0a..ddb6b12b 100644 --- a/app/Services/ExtraCharges/ExtraChargesInvoiceService.php +++ b/app/Services/ExtraCharges/ExtraChargesInvoiceService.php @@ -16,7 +16,7 @@ class ExtraChargesInvoiceService return array_map(function ($inv) { $id = (int) ($inv['id'] ?? 0); - $num = (string) ($inv['invoice_number'] ?? ('INV-'.$id)); + $num = (string) ($inv['invoice_number'] ?? ('INV-' . $id)); $status = strtolower((string) ($inv['status'] ?? '')); $balance = (float) ($inv['balance'] ?? 0); $issue = $inv['issue_date'] ?? null; @@ -28,8 +28,8 @@ class ExtraChargesInvoiceService 'balance' => $balance, 'issue_date' => $issue, 'text' => $num - .($status ? ' — '.ucfirst($status) : '') - .' (Bal: $'.number_format($balance, 2).')', + . ($status ? ' — ' . ucfirst($status) : '') + . ' (Bal: $' . number_format($balance, 2) . ')', ]; }, $rows); } diff --git a/app/Services/ExtraCharges/ExtraChargesMetaService.php b/app/Services/ExtraCharges/ExtraChargesMetaService.php index 0109c183..ae429e6a 100644 --- a/app/Services/ExtraCharges/ExtraChargesMetaService.php +++ b/app/Services/ExtraCharges/ExtraChargesMetaService.php @@ -21,7 +21,7 @@ class ExtraChargesMetaService foreach ($rows as $row) { $val = (string) ($row['school_year'] ?? ''); - if ($val !== '' && ! in_array($val, $schoolYears, true)) { + if ($val !== '' && !in_array($val, $schoolYears, true)) { $schoolYears[] = $val; } } @@ -39,7 +39,7 @@ class ExtraChargesMetaService foreach ($rows as $row) { $val = (string) ($row['school_year'] ?? ''); - if ($val !== '' && ! in_array($val, $schoolYears, true)) { + if ($val !== '' && !in_array($val, $schoolYears, true)) { $schoolYears[] = $val; } } @@ -53,7 +53,7 @@ class ExtraChargesMetaService $start = (int) $start; if ($start > 0) { for ($i = 1; $i <= 3; $i++) { - $schoolYears[] = ($start - $i).'-'.(($start - $i) + 1); + $schoolYears[] = ($start - $i) . '-' . (($start - $i) + 1); } } } diff --git a/app/Services/ExtraCharges/ExtraChargesParentService.php b/app/Services/ExtraCharges/ExtraChargesParentService.php index c5593ed7..d9b3ad37 100644 --- a/app/Services/ExtraCharges/ExtraChargesParentService.php +++ b/app/Services/ExtraCharges/ExtraChargesParentService.php @@ -32,14 +32,13 @@ class ExtraChargesParentService ->all(); return array_map(function ($row) { - $name = trim(($row['lastname'] ?? '').', '.($row['firstname'] ?? '')); + $name = trim(($row['lastname'] ?? '') . ', ' . ($row['firstname'] ?? '')); $email = $row['email'] ?? ''; - $label = $name !== ',' ? $name : ('User #'.$row['id']); + $label = $name !== ',' ? $name : ('User #' . $row['id']); if ($email) { - $label .= ' — '.$email; + $label .= ' — ' . $email; } - $label .= ' (ID: '.$row['id'].')'; - + $label .= ' (ID: ' . $row['id'] . ')'; return [ 'id' => (int) $row['id'], 'text' => $label, diff --git a/app/Services/Families/FamilyMutationService.php b/app/Services/Families/FamilyMutationService.php index 78dd2fb4..78f188ab 100644 --- a/app/Services/Families/FamilyMutationService.php +++ b/app/Services/Families/FamilyMutationService.php @@ -67,7 +67,7 @@ class FamilyMutationService } $familyId = $this->familyIdFromStudentPrimary($studentId); - if (! $familyId) { + if (!$familyId) { return ['ok' => false, 'message' => 'No primary family found for this student']; } @@ -83,13 +83,13 @@ class FamilyMutationService } $familyId = $this->familyIdFromStudentPrimary($studentId); - if (! $familyId) { + if (!$familyId) { return ['ok' => false, 'message' => 'No primary family found for this student']; } return DB::transaction(function () use ($email, $firstname, $lastname, $relation, $familyId) { $user = User::query()->where('email', $email)->first(); - if (! $user) { + if (!$user) { $user = User::query()->create([ 'firstname' => (string) ($firstname ?? ''), 'lastname' => (string) ($lastname ?? ''), @@ -167,7 +167,7 @@ class FamilyMutationService { $legacyTable = 'parents'; $this->ensureTablesExist(['families', 'family_students', 'family_guardians']); - if (! Schema::hasTable($legacyTable)) { + if (!Schema::hasTable($legacyTable)) { return ['ok' => false, 'message' => "Legacy table '{$legacyTable}' not found"]; } @@ -192,7 +192,6 @@ class FamilyMutationService if ($firstId <= 0 || ($secondId <= 0 && $email === '')) { $skipped++; - continue; } @@ -204,7 +203,7 @@ class FamilyMutationService $userId = $secondId; } else { $user = User::query()->where('email', $email)->first(); - if (! $user) { + if (!$user) { $user = User::query()->create([ 'firstname' => (string) ($r['firstname'] ?? ''), 'lastname' => (string) ($r['lastname'] ?? ''), @@ -252,7 +251,7 @@ class FamilyMutationService private function ensureFamilyForPrimaryParent(int $primaryUserId, int &$createdCounter): int { - $code = 'FAM-'.$primaryUserId; + $code = 'FAM-' . $primaryUserId; $row = Family::query()->where('family_code', $code)->first(); if ($row) { return (int) $row->id; @@ -260,7 +259,7 @@ class FamilyMutationService $family = Family::query()->create([ 'family_code' => $code, - 'household_name' => 'Family of User '.$primaryUserId, + 'household_name' => 'Family of User ' . $primaryUserId, 'is_active' => 1, ]); $createdCounter++; @@ -310,11 +309,11 @@ class FamilyMutationService private function familyIdFromStudentPrimary(int $studentId): ?int { $student = Student::query()->select('parent_id')->find($studentId); - if (! $student || empty($student->parent_id)) { + if (!$student || empty($student->parent_id)) { return null; } - $code = 'FAM-'.(int) $student->parent_id; + $code = 'FAM-' . (int) $student->parent_id; $row = Family::query()->select('id')->where('family_code', $code)->first(); if ($row) { return (int) $row->id; @@ -332,7 +331,7 @@ class FamilyMutationService private function ensureTablesExist(array $tables): void { foreach ($tables as $table) { - if (! Schema::hasTable($table)) { + if (!Schema::hasTable($table)) { Log::warning('Family tables missing', ['table' => $table]); throw new \RuntimeException("Missing required table '{$table}'. Run migrations."); } diff --git a/app/Services/Families/FamilyNotificationService.php b/app/Services/Families/FamilyNotificationService.php index 119dd496..7b31cbc4 100644 --- a/app/Services/Families/FamilyNotificationService.php +++ b/app/Services/Families/FamilyNotificationService.php @@ -6,7 +6,9 @@ use App\Services\Email\EmailDispatchService; class FamilyNotificationService { - public function __construct(private EmailDispatchService $dispatch) {} + public function __construct(private EmailDispatchService $dispatch) + { + } public function sendComposeEmail( string $recipient, diff --git a/app/Services/Families/FamilyQueryService.php b/app/Services/Families/FamilyQueryService.php index cb0ac923..528bb667 100644 --- a/app/Services/Families/FamilyQueryService.php +++ b/app/Services/Families/FamilyQueryService.php @@ -5,11 +5,14 @@ namespace App\Services\Families; use App\Models\Family; use App\Models\Student; use App\Models\StudentClass; +use App\Models\User; use Illuminate\Support\Facades\DB; class FamilyQueryService { - public function __construct(private FamilyFinanceService $finance) {} + public function __construct(private FamilyFinanceService $finance) + { + } public function listStudentsForSelect(): array { @@ -29,7 +32,7 @@ class FamilyQueryService return []; } - $qs = '%'.str_replace(['%', '_'], ['\\%', '\\_'], $query).'%'; + $qs = '%' . str_replace(['%', '_'], ['\\%', '\\_'], $query) . '%'; $students = DB::table('students') ->select('id', 'firstname', 'lastname') @@ -60,7 +63,7 @@ class FamilyQueryService $items[] = [ 'type' => 'student', 'id' => (int) ($s['id'] ?? 0), - 'label' => trim(($s['firstname'] ?? '').' '.($s['lastname'] ?? '')), + 'label' => trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? '')), 'sub' => 'Student', ]; } @@ -68,8 +71,8 @@ class FamilyQueryService $items[] = [ 'type' => 'guardian', 'id' => (int) ($g['id'] ?? 0), - 'label' => trim(($g['firstname'] ?? '').' '.($g['lastname'] ?? '')), - 'sub' => trim(($g['email'] ?? '').' '.($g['cellphone'] ?? '')), + 'label' => trim(($g['firstname'] ?? '') . ' ' . ($g['lastname'] ?? '')), + 'sub' => trim(($g['email'] ?? '') . ' ' . ($g['cellphone'] ?? '')), ]; } @@ -90,7 +93,7 @@ class FamilyQueryService ->orderBy('s.firstname') ->select('s.id as student_id') ->first(); - if ($row && ! empty($row->student_id)) { + if ($row && !empty($row->student_id)) { return (int) $row->student_id; } @@ -233,7 +236,7 @@ class FamilyQueryService unset($fam); $data['families'] = $families; - if (! empty($families)) { + if (!empty($families)) { $familyId = (int) ($families[0]['id'] ?? 0); $data['guardians'] = $familyId ? $this->listGuardiansByFamily($familyId) : []; } @@ -303,7 +306,7 @@ class FamilyQueryService ) ->find($familyId); - if (! $family) { + if (!$family) { return null; } @@ -361,7 +364,7 @@ class FamilyQueryService foreach ($guardians as $g) { $gid = (int) ($g['user_id'] ?? 0); if ($gid > 0) { - $guardianMap[$gid] = trim(($g['firstname'] ?? '').' '.($g['lastname'] ?? '')); + $guardianMap[$gid] = trim(($g['firstname'] ?? '') . ' ' . ($g['lastname'] ?? '')); } } @@ -375,7 +378,7 @@ class FamilyQueryService foreach ($rows as &$row) { $pid = (int) ($row['parent_id'] ?? 0); - $row['parent_label'] = $guardianMap[$pid] ?? ('Parent #'.$pid); + $row['parent_label'] = $guardianMap[$pid] ?? ('Parent #' . $pid); } unset($row); diff --git a/app/Services/FeeCalculationService.php b/app/Services/FeeCalculationService.php index ed9505bf..619a7d74 100644 --- a/app/Services/FeeCalculationService.php +++ b/app/Services/FeeCalculationService.php @@ -8,12 +8,12 @@ class FeeCalculationService { public function __construct( private FeeRefundCalculatorService $refundCalculator - ) {} + ) { + } public function calculateRefund(array $students, int $parentId): float { $result = $this->refundCalculator->calculateRefund($students, $parentId); - return (float) ($result['refund_amount'] ?? 0); } } diff --git a/app/Services/Fees/FeeGradeService.php b/app/Services/Fees/FeeGradeService.php index 9505b346..5933fd76 100644 --- a/app/Services/Fees/FeeGradeService.php +++ b/app/Services/Fees/FeeGradeService.php @@ -7,7 +7,6 @@ class FeeGradeService public function normalizeGrade(?string $grade): string { $normalized = strtoupper(trim((string) $grade)); - return str_replace([' ', '-'], '', $normalized); } diff --git a/app/Services/Fees/FeeRefundCalculatorService.php b/app/Services/Fees/FeeRefundCalculatorService.php index 2ba2391e..65cc299e 100644 --- a/app/Services/Fees/FeeRefundCalculatorService.php +++ b/app/Services/Fees/FeeRefundCalculatorService.php @@ -10,7 +10,8 @@ class FeeRefundCalculatorService public function __construct( private FeeConfigService $config, private FeeStudentFeeService $studentFees - ) {} + ) { + } public function calculateRefund(array $students, int $parentId): array { @@ -25,7 +26,6 @@ class FeeRefundCalculatorService 'parent_id' => $parentId, 'school_year' => $schoolYear, ]); - return $this->resultPayload(0.0, $totalPaid, $refundDeadline, $schoolEndDate, $weeksOfStudy, 0, []); } @@ -36,7 +36,6 @@ class FeeRefundCalculatorService 'parent_id' => $parentId, 'registered_count' => count($registered), ]); - return $this->resultPayload(0.0, $totalPaid, $refundDeadline, $schoolEndDate, $weeksOfStudy, 0, []); } @@ -58,7 +57,7 @@ class FeeRefundCalculatorService $withdrawnWithFees = array_values(array_filter( $allStudents, - fn (array $student): bool => ! empty($student['_is_withdrawn']) + fn (array $student): bool => !empty($student['_is_withdrawn']) )); $refundAmount = 0.0; @@ -83,32 +82,29 @@ class FeeRefundCalculatorService 'reason' => null, ]; - if (! $withdrawalDate) { + if (!$withdrawalDate) { $entry['reason'] = 'missing_withdrawal_date'; Log::warning('Refund skipped for student: missing withdrawal date', [ 'parent_id' => $parentId, 'student_id' => $studentId, ]); $studentBreakdown[] = $entry; - continue; } - if (! $refundDeadline || strtotime($withdrawalDate) > strtotime($refundDeadline)) { + if (!$refundDeadline || strtotime($withdrawalDate) > strtotime($refundDeadline)) { $entry['reason'] = 'after_refund_deadline'; $studentBreakdown[] = $entry; - continue; } - if (! $schoolEndDate) { + if (!$schoolEndDate) { $entry['reason'] = 'missing_school_end_date'; Log::warning('Refund skipped for student: missing school end date', [ 'parent_id' => $parentId, 'student_id' => $studentId, ]); $studentBreakdown[] = $entry; - continue; } @@ -121,7 +117,6 @@ class FeeRefundCalculatorService 'weeks_of_study' => $weeksOfStudy, ]); $studentBreakdown[] = $entry; - continue; } @@ -158,7 +153,7 @@ class FeeRefundCalculatorService if ($uncappedRefund > 0) { $ratio = $totalPaid / $uncappedRefund; foreach ($studentBreakdown as &$row) { - if (! empty($row['eligible'])) { + if (!empty($row['eligible'])) { $row['refund_amount'] = round($row['refund_amount'] * $ratio, 2); } } @@ -197,7 +192,6 @@ class FeeRefundCalculatorService foreach ($students as $student) { if ($this->studentFees->isWithdrawn($student)) { $withdrawn[] = $student; - continue; } @@ -219,7 +213,6 @@ class FeeRefundCalculatorService } $daysRemaining = $withdrawDateObj->diff($schoolEndDateObj)->days; - return (int) min($weeksOfStudy, max(0, (int) ceil($daysRemaining / 7))); } diff --git a/app/Services/Fees/FeeRefundDetailService.php b/app/Services/Fees/FeeRefundDetailService.php index ecb89d93..2affe056 100644 --- a/app/Services/Fees/FeeRefundDetailService.php +++ b/app/Services/Fees/FeeRefundDetailService.php @@ -37,12 +37,11 @@ class FeeRefundDetailService $tuitionStudents = $registeredKids; foreach ($withdrawnKids as $kid) { $rawDate = $kid['withdrawal_date'] ?? null; - if (empty($rawDate) || ! $deadline) { + if (empty($rawDate) || !$deadline) { Log::warning('Missing withdrawal date or deadline; billing withdrawn student.', [ 'student_id' => $kid['student_id'] ?? null, ]); $tuitionStudents[] = $kid; - continue; } @@ -53,7 +52,6 @@ class FeeRefundDetailService 'student_id' => $kid['student_id'] ?? null, ]); $tuitionStudents[] = $kid; - continue; } @@ -64,13 +62,12 @@ class FeeRefundDetailService $tuitionStudents = array_values(array_filter($tuitionStudents, function ($student) use ($schoolYear) { $sid = (int) ($student['student_id'] ?? 0); - return $sid > 0 && StudentClass::hasNonEventAssignment($sid, $schoolYear); })); foreach ($tuitionStudents as &$student) { $name = null; - if (! empty($student['class_section_id'])) { + if (!empty($student['class_section_id'])) { $name = ClassSection::getClassSectionNameBySectionId($student['class_section_id']); } $student['grade_name'] = is_string($name) ? strtoupper(trim($name)) : 'N/A'; @@ -132,7 +129,7 @@ class FeeRefundDetailService if ($bookPriceRaw === null || $bookPriceRaw === '') { return ['ok' => false, 'error' => 'Book price is not configured.']; } - if (! is_numeric($bookPriceRaw)) { + if (!is_numeric($bookPriceRaw)) { return ['ok' => false, 'error' => 'Book price must be numeric.']; } $bookPrice = round((float) $bookPriceRaw, 2); @@ -149,10 +146,9 @@ class FeeRefundDetailService $status = (string) ($student['enrollment_status'] ?? ''); if (in_array($status, ['enrolled', 'payment pending'], true)) { $registered[] = $student; - continue; } - if (! in_array($status, ['withdrawn', 'refund pending', 'withdraw under review'], true)) { + if (!in_array($status, ['withdrawn', 'refund pending', 'withdraw under review'], true)) { continue; } $hasWithdrawn = true; @@ -173,7 +169,7 @@ class FeeRefundDetailService } } - if (! $hasWithdrawn) { + if (!$hasWithdrawn) { return ['ok' => false, 'error' => 'No withdrawn students found for refund evaluation.']; } @@ -207,7 +203,7 @@ class FeeRefundDetailService } } - $eligible = ! empty($withdrawnEligible); + $eligible = !empty($withdrawnEligible); $refundAmount = 0.0; $debitAmount = 0.0; @@ -234,9 +230,9 @@ class FeeRefundDetailService $refundableCash = min($totalPaid, $refundableTuition); $raw = round($refundableCash - $bookPrice, 2); - if ($raw > 0 && ! $fullDiscount) { + if ($raw > 0 && !$fullDiscount) { $refundAmount = $raw; - } elseif ($raw < 0 && ! $fullDiscount) { + } elseif ($raw < 0 && !$fullDiscount) { $debitAmount = abs($raw); } } @@ -263,7 +259,6 @@ class FeeRefundDetailService public function calculateRefund(array $students, int $parentId): float { $result = $this->calculateRefundDetails($students, $parentId); - return (float) ($result['refund_amount'] ?? 0.0); } @@ -271,7 +266,6 @@ class FeeRefundDetailService { $resolvedGradeFee = $gradeFee ?? (int) (Configuration::getConfig('grade_fee') ?? 9); $grades = new InvoiceGradeService($resolvedGradeFee); - return $grades->getGradeLevel($grade); } @@ -279,7 +273,6 @@ class FeeRefundDetailService { $resolvedGradeFee = $gradeFee ?? (int) (Configuration::getConfig('grade_fee') ?? 9); $grades = new InvoiceGradeService($resolvedGradeFee); - return $grades->compareGrades((string) $gradeA, (string) $gradeB); } diff --git a/app/Services/Fees/FeeStudentFeeService.php b/app/Services/Fees/FeeStudentFeeService.php index 7c6b1a14..546d92e1 100644 --- a/app/Services/Fees/FeeStudentFeeService.php +++ b/app/Services/Fees/FeeStudentFeeService.php @@ -8,23 +8,19 @@ use Illuminate\Support\Facades\Log; class FeeStudentFeeService { public const CATEGORY_FIRST_REGULAR = 'first_regular'; - public const CATEGORY_ADDITIONAL_REGULAR = 'additional_regular'; - public const CATEGORY_YOUTH = 'youth'; - public const CATEGORY_NOT_BILLABLE = 'not_billable'; private const BILLABLE_ENROLLMENT_STATUSES = ['enrolled', 'payment pending']; - private const WITHDRAWN_ENROLLMENT_STATUSES = ['withdrawn', 'refund pending', 'withdraw under review']; - private const ACCEPTED_ADMISSION_STATUS = 'accepted'; public function __construct( private FeeGradeService $grades, private FeeConfigService $config - ) {} + ) { + } /** * Normalize grades, sort by grade level, and assign a tuition fee to each @@ -134,7 +130,6 @@ class FeeStudentFeeService $nonBillable = array_map(function (array $student): array { $student['fee_category'] = self::CATEGORY_NOT_BILLABLE; $student['tuition_fee'] = 0.0; - return $student; }, $nonBillable); @@ -153,7 +148,7 @@ class FeeStudentFeeService $studentRows[] = [ 'student_id' => $student['student_id'] ?? null, - 'student_name' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')), + 'student_name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')), 'grade' => $student['grade'] ?? null, 'grade_level' => $student['grade_level'] ?? null, 'enrollment_status' => $student['enrollment_status'] ?? null, @@ -197,7 +192,6 @@ class FeeStudentFeeService public function isWithdrawn(array $student): bool { $status = strtolower((string) ($student['enrollment_status'] ?? '')); - return in_array($status, self::WITHDRAWN_ENROLLMENT_STATUSES, true); } diff --git a/app/Services/Fees/TuitionCalculationService.php b/app/Services/Fees/TuitionCalculationService.php index 18d6d640..cfeceb33 100644 --- a/app/Services/Fees/TuitionCalculationService.php +++ b/app/Services/Fees/TuitionCalculationService.php @@ -23,14 +23,16 @@ class TuitionCalculationService public function __construct( private FeeConfigService $config, private FeeStudentFeeService $studentFees - ) {} + ) { + } /** * Produce a family + per-student tuition calculation. * - * @param array $students Each item may include: student_id, firstname, - * lastname, grade, class_section_id, enrollment_status, - * admission_status, discount_amount. + * @param array $students Each item may include: student_id, firstname, + * lastname, grade, class_section_id, enrollment_status, + * admission_status, discount_amount. + * * @return array{ * school_year: string, * fees: array, diff --git a/app/Services/Files/ExamDraftDownloadNameService.php b/app/Services/Files/ExamDraftDownloadNameService.php index ca156993..e08fd3a8 100644 --- a/app/Services/Files/ExamDraftDownloadNameService.php +++ b/app/Services/Files/ExamDraftDownloadNameService.php @@ -13,15 +13,15 @@ class ExamDraftDownloadNameService $row = DB::table('exam_drafts as ed') ->select('ed.version', 'ed.exam_type', 'ed.class_section_id', 'cs.class_section_name') ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'ed.class_section_id') - ->where('ed.'.$column, $filename) + ->where('ed.' . $column, $filename) ->limit(1) ->first(); $row = $row ? (array) $row : []; - $classLabel = trim((string) ($row['class_section_name'] ?? ('Class'.($row['class_section_id'] ?? '0')))); + $classLabel = trim((string) ($row['class_section_name'] ?? ('Class' . ($row['class_section_id'] ?? '0')))); $typeLabel = trim((string) ($row['exam_type'] ?? 'Exam')); - $version = 'v'.max(1, (int) ($row['version'] ?? 1)); + $version = 'v' . max(1, (int) ($row['version'] ?? 1)); $parts = array_filter([ $this->slugify($classLabel), @@ -40,7 +40,6 @@ class ExamDraftDownloadNameService if ($value === '') { return 'Exam'; } - return mb_strtolower($value); } } diff --git a/app/Services/Files/FileServeService.php b/app/Services/Files/FileServeService.php index e0424468..fb39b566 100644 --- a/app/Services/Files/FileServeService.php +++ b/app/Services/Files/FileServeService.php @@ -35,7 +35,7 @@ class FileServeService $headers = [ 'Content-Type' => $meta['mime'], - 'Content-Disposition' => 'inline; filename="'.$meta['download_name'].'"', + 'Content-Disposition' => 'inline; filename="' . $meta['download_name'] . '"', 'Content-Length' => (string) $meta['size'], 'ETag' => $meta['etag'], 'Last-Modified' => $meta['last_modified'], @@ -53,20 +53,20 @@ class FileServeService } $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); - if (! in_array($ext, $allowedExtensions, true)) { + if (!in_array($ext, $allowedExtensions, true)) { throw new HttpException(404, 'File not found'); } - $path = rtrim($baseDir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$name; - if (! is_file($path)) { + $path = rtrim($baseDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $name; + if (!is_file($path)) { throw new HttpException(404, 'File not found'); } $mime = $this->detectMime($path); $mtime = filemtime($path) ?: time(); $size = filesize($path) ?: 0; - $etag = md5($name.'|'.$mtime.'|'.$size); - $downloadName = $downloadName ? $downloadName.'.'.$ext : $name; + $etag = md5($name . '|' . $mtime . '|' . $size); + $downloadName = $downloadName ? $downloadName . '.' . $ext : $name; return [ 'name' => $name, @@ -76,7 +76,7 @@ class FileServeService 'size' => $size, 'etag' => $etag, 'download_name' => $downloadName, - 'last_modified' => gmdate('D, d M Y H:i:s', $mtime).' GMT', + 'last_modified' => gmdate('D, d M Y H:i:s', $mtime) . ' GMT', ]; } diff --git a/app/Services/Finance/FinanceNotificationLogService.php b/app/Services/Finance/FinanceNotificationLogService.php index 5a4531be..33229701 100644 --- a/app/Services/Finance/FinanceNotificationLogService.php +++ b/app/Services/Finance/FinanceNotificationLogService.php @@ -16,36 +16,25 @@ class FinanceNotificationLogService 'failed_at' => $status === 'failed' ? now() : null, 'created_by' => $actorId, ])); - return $log->toArray(); } public function list(array $filters): array { $q = FinanceNotificationLog::query(); - foreach (['status', 'notification_type', 'parent_id'] as $field) { - if (! empty($filters[$field])) { - $q->where($field, $filters[$field]); - } - } - if (! empty($filters['date_from'])) { - $q->whereDate('created_at', '>=', $filters['date_from']); - } - if (! empty($filters['date_to'])) { - $q->whereDate('created_at', '<=', $filters['date_to']); - } - - return ['rows' => $q->orderByDesc('id')->paginate((int) ($filters['per_page'] ?? 25))]; + foreach (['status','notification_type','parent_id'] as $field) if (!empty($filters[$field])) $q->where($field, $filters[$field]); + if (!empty($filters['date_from'])) $q->whereDate('created_at', '>=', $filters['date_from']); + if (!empty($filters['date_to'])) $q->whereDate('created_at', '<=', $filters['date_to']); + return ['rows' => $q->orderByDesc('id')->paginate((int)($filters['per_page'] ?? 25))]; } public function nextReceiptNumber(string $schoolYear): string { return DB::transaction(function () use ($schoolYear) { $seq = FinanceReceiptSequence::query()->lockForUpdate()->firstOrCreate(['school_year' => $schoolYear], ['prefix' => 'R', 'next_number' => 1]); - $number = $seq->prefix.'-'.$schoolYear.'-'.str_pad((string) $seq->next_number, 6, '0', STR_PAD_LEFT); + $number = $seq->prefix . '-' . $schoolYear . '-' . str_pad((string) $seq->next_number, 6, '0', STR_PAD_LEFT); $seq->next_number = $seq->next_number + 1; $seq->save(); - return $number; }); } diff --git a/app/Services/Finance/FinancialChartService.php b/app/Services/Finance/FinancialChartService.php index c2f7609c..8beea7a1 100644 --- a/app/Services/Finance/FinancialChartService.php +++ b/app/Services/Finance/FinancialChartService.php @@ -60,9 +60,9 @@ class FinancialChartService private function downloadChart(array $chartData, string $filename): ?string { $baseUrl = 'https://quickchart.io/chart?c='; - $url = $baseUrl.urlencode(json_encode($chartData)); + $url = $baseUrl . urlencode(json_encode($chartData)); $targetDir = storage_path('app/reports'); - if (! is_dir($targetDir) && ! mkdir($targetDir, 0775, true) && ! is_dir($targetDir)) { + if (!is_dir($targetDir) && !mkdir($targetDir, 0775, true) && !is_dir($targetDir)) { return null; } @@ -71,9 +71,8 @@ class FinancialChartService if ($contents === false) { return null; } - $path = $targetDir.DIRECTORY_SEPARATOR.$filename; + $path = $targetDir . DIRECTORY_SEPARATOR . $filename; file_put_contents($path, $contents); - return $path; } catch (\Throwable $e) { return null; diff --git a/app/Services/Finance/FinancialPaymentService.php b/app/Services/Finance/FinancialPaymentService.php index c22a7b6d..5f55bdf7 100644 --- a/app/Services/Finance/FinancialPaymentService.php +++ b/app/Services/Finance/FinancialPaymentService.php @@ -50,7 +50,7 @@ class FinancialPaymentService } $method = (string) ($row['method'] ?? ''); $amount = (float) ($row['amount'] ?? 0); - if (! isset($breakdown[$invoiceId])) { + if (!isset($breakdown[$invoiceId])) { $breakdown[$invoiceId] = []; } $breakdown[$invoiceId][$method] = $amount; @@ -85,13 +85,13 @@ class FinancialPaymentService { $query = DB::table('payments'); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $query->where('school_year', $schoolYear); } - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $query->whereRaw('DATE(payment_date) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $query->whereRaw('DATE(payment_date) <= ?', [$dateTo]); } diff --git a/app/Services/Finance/FinancialPdfReportService.php b/app/Services/Finance/FinancialPdfReportService.php index bd1c3be9..0f7c28b1 100644 --- a/app/Services/Finance/FinancialPdfReportService.php +++ b/app/Services/Finance/FinancialPdfReportService.php @@ -4,14 +4,16 @@ namespace App\Services\Finance; class FinancialPdfReportService { - public function __construct(private FinancialChartService $charts) {} + public function __construct(private FinancialChartService $charts) + { + } public function buildPdf(array $summary): string { - $pdf = new \FPDF; + $pdf = new \FPDF(); $pdf->AddPage(); $pdf->SetFont('Arial', 'B', 16); - $pdf->Cell(0, 10, 'Financial Report for School Year: '.($summary['schoolYear'] ?? ''), 0, 1, 'C'); + $pdf->Cell(0, 10, 'Financial Report for School Year: ' . ($summary['schoolYear'] ?? ''), 0, 1, 'C'); $pdf->Ln(10); $pdf->SetFont('Arial', 'B', 12); @@ -35,12 +37,12 @@ class FinancialPdfReportService $pdf->SetFont('Arial', '', 11); foreach ($rows as $label => $amount) { $pdf->Cell(130, 10, $label, 1); - $pdf->Cell(60, 10, '$'.number_format((float) $amount, 2), 1); + $pdf->Cell(60, 10, '$' . number_format((float) $amount, 2), 1); $pdf->Ln(); } $barChart = $this->charts->generateBarChart($summary); - if (! empty($barChart) && file_exists($barChart)) { + if (!empty($barChart) && file_exists($barChart)) { $pdf->Ln(10); $pdf->SetFont('Arial', 'B', 12); $pdf->Cell(0, 10, 'Summary Graph', 0, 1); @@ -48,7 +50,7 @@ class FinancialPdfReportService } $pieChart = $this->charts->generatePieChart($summary); - if (! empty($pieChart) && file_exists($pieChart)) { + if (!empty($pieChart) && file_exists($pieChart)) { $pdf->Ln(10); $pdf->SetFont('Arial', 'B', 12); $pdf->Cell(0, 10, 'Expense Breakdown', 0, 1); diff --git a/app/Services/Finance/FinancialReportService.php b/app/Services/Finance/FinancialReportService.php index 1fe0c70c..16ab30ee 100644 --- a/app/Services/Finance/FinancialReportService.php +++ b/app/Services/Finance/FinancialReportService.php @@ -9,7 +9,8 @@ class FinancialReportService public function __construct( private FinancialPaymentService $payments, private FinancialSchoolYearService $schoolYears - ) {} + ) { + } public function getReport(?string $dateFrom, ?string $dateTo, ?string $schoolYear): array { @@ -22,7 +23,7 @@ class FinancialReportService $expenseQuery = DB::table('expenses'); $reimbQuery = DB::table('reimbursements'); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $invoiceQuery->where('invoices.school_year', $schoolYear); $refundQuery->where('school_year', $schoolYear); $discountQuery->where('school_year', $schoolYear); @@ -30,7 +31,7 @@ class FinancialReportService $reimbQuery->where('school_year', $schoolYear); } - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $invoiceQuery->whereRaw('DATE(COALESCE(invoices.issue_date, invoices.created_at)) >= ?', [$dateFrom]); $refundQuery->whereRaw('DATE(COALESCE(refunded_at, created_at)) >= ?', [$dateFrom]); $discountQuery->whereRaw('DATE(COALESCE(used_at, created_at)) >= ?', [$dateFrom]); @@ -38,7 +39,7 @@ class FinancialReportService $reimbQuery->whereRaw('DATE(created_at) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $invoiceQuery->whereRaw('DATE(COALESCE(invoices.issue_date, invoices.created_at)) <= ?', [$dateTo]); $refundQuery->whereRaw('DATE(COALESCE(refunded_at, created_at)) <= ?', [$dateTo]); $discountQuery->whereRaw('DATE(COALESCE(used_at, created_at)) <= ?', [$dateTo]); diff --git a/app/Services/Finance/FinancialSchoolYearService.php b/app/Services/Finance/FinancialSchoolYearService.php index 04038ef4..2cb61a51 100644 --- a/app/Services/Finance/FinancialSchoolYearService.php +++ b/app/Services/Finance/FinancialSchoolYearService.php @@ -19,7 +19,7 @@ class FinancialSchoolYearService ->values() ->all(); - if (empty($years) && ! empty($fallbackYear)) { + if (empty($years) && !empty($fallbackYear)) { $years[] = (string) $fallbackYear; } diff --git a/app/Services/Finance/FinancialSummaryService.php b/app/Services/Finance/FinancialSummaryService.php index a5980ce1..c0df7c95 100644 --- a/app/Services/Finance/FinancialSummaryService.php +++ b/app/Services/Finance/FinancialSummaryService.php @@ -10,7 +10,8 @@ class FinancialSummaryService { public function __construct( private FinancialDonationRecipientService $donationRecipients - ) {} + ) { + } public function getSummary(?string $dateFrom, ?string $dateTo, ?string $schoolYear): array { @@ -18,10 +19,10 @@ class FinancialSummaryService $derivedDateFrom = null; $derivedDateTo = null; - if (! empty($schoolYear) && empty($dateFrom) && empty($dateTo)) { + if (!empty($schoolYear) && empty($dateFrom) && empty($dateTo)) { if (preg_match('/^(\\d{4})[^\\d]?(\\d{4})$/', $schoolYear, $m)) { - $derivedDateFrom = $m[1].'-01-01'; - $derivedDateTo = $m[2].'-12-31'; + $derivedDateFrom = $m[1] . '-01-01'; + $derivedDateTo = $m[2] . '-12-31'; } } @@ -29,10 +30,10 @@ class FinancialSummaryService $invoiceDateTo = $dateTo ?: $derivedDateTo; $invoiceQuery = DB::table('invoices')->where('school_year', $schoolYear); - if (! empty($invoiceDateFrom)) { + if (!empty($invoiceDateFrom)) { $invoiceQuery->whereRaw('DATE(COALESCE(issue_date, created_at)) >= ?', [$invoiceDateFrom]); } - if (! empty($invoiceDateTo)) { + if (!empty($invoiceDateTo)) { $invoiceQuery->whereRaw('DATE(COALESCE(issue_date, created_at)) <= ?', [$invoiceDateTo]); } $invoices = $invoiceQuery->get()->map(fn ($row) => (array) $row)->all(); @@ -40,7 +41,6 @@ class FinancialSummaryService $invoiceIds = array_values(array_unique(array_filter(array_map(static function ($row) { $id = (int) ($row['id'] ?? 0); - return $id > 0 ? $id : null; }, $invoices)))); @@ -54,7 +54,7 @@ class FinancialSummaryService $paidByInvoice = []; $discountByInvoice = []; $refundByInvoice = []; - if (! empty($invoiceIds)) { + if (!empty($invoiceIds)) { $paidByInvoice = $this->paymentsByInvoiceIds($invoiceIds, $schoolYear, $invoiceDateFrom, $invoiceDateTo); $discountByInvoice = $this->discountsByInvoiceIds($invoiceIds, $dateFrom, $dateTo); $refundByInvoice = $this->refundsByInvoiceIds($invoiceIds, $dateFrom, $dateTo); @@ -99,15 +99,14 @@ class FinancialSummaryService ->where('ac.school_year', $schoolYear) ->where('ac.status', '!=', 'void'); - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $query->whereRaw('DATE(ac.due_date) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $query->whereRaw('DATE(ac.due_date) <= ?', [$dateTo]); } $row = (array) $query->first(); - return (float) ($row['amount'] ?? 0); } @@ -124,10 +123,10 @@ class FinancialSummaryService }) ->groupBy('ac.parent_id'); - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $query->whereRaw('DATE(ac.due_date) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $query->whereRaw('DATE(ac.due_date) <= ?', [$dateTo]); } @@ -147,10 +146,10 @@ class FinancialSummaryService private function sumPayments(string $schoolYear, ?string $dateFrom, ?string $dateTo): float { $query = DB::table('payments')->where('school_year', $schoolYear); - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $query->whereRaw('DATE(payment_date) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $query->whereRaw('DATE(payment_date) <= ?', [$dateTo]); } @@ -167,7 +166,6 @@ class FinancialSummaryService } $row = (array) $query->selectRaw('COALESCE(SUM(paid_amount), 0) AS paid_amount')->first(); - return (float) ($row['paid_amount'] ?? 0); } @@ -178,10 +176,10 @@ class FinancialSummaryService ->whereIn('invoice_id', $invoiceIds) ->where('school_year', $schoolYear); - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $query->whereRaw('DATE(payment_date) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $query->whereRaw('DATE(payment_date) <= ?', [$dateTo]); } @@ -205,7 +203,6 @@ class FinancialSummaryService $map[$invoiceId] = (float) ($row['total_paid'] ?? 0); } } - return $map; } @@ -215,10 +212,10 @@ class FinancialSummaryService ->selectRaw('invoice_id, COALESCE(SUM(discount_amount),0) AS total_disc') ->whereIn('invoice_id', $invoiceIds); - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $query->whereRaw('DATE(COALESCE(used_at, created_at)) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $query->whereRaw('DATE(COALESCE(used_at, created_at)) <= ?', [$dateTo]); } @@ -230,7 +227,6 @@ class FinancialSummaryService $map[$invoiceId] = (float) ($row['total_disc'] ?? 0); } } - return $map; } @@ -241,10 +237,10 @@ class FinancialSummaryService ->whereIn('invoice_id', $invoiceIds) ->whereIn('status', ['Partial', 'Paid']); - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $query->whereRaw('DATE(COALESCE(refunded_at, created_at)) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $query->whereRaw('DATE(COALESCE(refunded_at, created_at)) <= ?', [$dateTo]); } @@ -256,22 +252,20 @@ class FinancialSummaryService $map[$invoiceId] = (float) ($row['total_refund'] ?? 0); } } - return $map; } private function sumExpenses(string $schoolYear, ?string $dateFrom, ?string $dateTo): float { $query = DB::table('expenses')->where('school_year', $schoolYear); - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $query->whereRaw('DATE(created_at) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $query->whereRaw('DATE(created_at) <= ?', [$dateTo]); } $row = (array) $query->selectRaw('COALESCE(SUM(amount), 0) AS amount')->first(); - return (float) ($row['amount'] ?? 0); } @@ -283,7 +277,7 @@ class FinancialSummaryService ->selectRaw('COALESCE(SUM(r.amount),0) AS amount') ->leftJoin('expenses as e', 'e.id', '=', 'r.expense_id'); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $query->where(function ($q) use ($schoolYear, $normalizedYear) { $q->where(function ($q2) use ($schoolYear, $normalizedYear) { $q2->where('r.school_year', $schoolYear) @@ -304,10 +298,10 @@ class FinancialSummaryService }); } - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $query->whereRaw('DATE(COALESCE(r.created_at, e.created_at)) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $query->whereRaw('DATE(COALESCE(r.created_at, e.created_at)) <= ?', [$dateTo]); } @@ -323,7 +317,7 @@ class FinancialSummaryService ->whereNull('bi.unassigned_at') ->whereNull('r.id'); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $batchFallback->where(function ($q) use ($schoolYear, $normalizedYear) { $q->where('e.school_year', $schoolYear) ->orWhereRaw( @@ -333,10 +327,10 @@ class FinancialSummaryService }); } - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $batchFallback->whereRaw('DATE(COALESCE(e.created_at, b.closed_at)) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $batchFallback->whereRaw('DATE(COALESCE(e.created_at, b.closed_at)) <= ?', [$dateTo]); } @@ -352,10 +346,10 @@ class FinancialSummaryService ->where('school_year', $schoolYear) ->where('category', 'Donation'); - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $expenseQuery->whereRaw('DATE(created_at) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $expenseQuery->whereRaw('DATE(created_at) <= ?', [$dateTo]); } @@ -364,14 +358,14 @@ class FinancialSummaryService $donationReimb = 0.0; $recipientIds = $this->donationRecipients->recipientIds(); - if (! empty($recipientIds)) { + if (!empty($recipientIds)) { $normalizedYear = preg_replace('/[^0-9]/', '', (string) $schoolYear); $donationQuery = DB::table('reimbursements as r') ->selectRaw('COALESCE(SUM(r.amount),0) AS amount') ->leftJoin('expenses as e', 'e.id', '=', 'r.expense_id') ->whereIn('r.reimbursed_to', $recipientIds); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $donationQuery->where(function ($q) use ($schoolYear, $normalizedYear) { $q->where(function ($q2) use ($schoolYear, $normalizedYear) { $q2->where('r.school_year', $schoolYear) @@ -392,10 +386,10 @@ class FinancialSummaryService }); } - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $donationQuery->whereRaw('DATE(COALESCE(r.created_at, e.created_at)) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $donationQuery->whereRaw('DATE(COALESCE(r.created_at, e.created_at)) <= ?', [$dateTo]); } @@ -416,15 +410,14 @@ class FinancialSummaryService ->whereIn('status', ['Partial', 'Paid']) ->whereNotNull('refund_paid_amount'); - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $query->whereRaw('DATE(COALESCE(refunded_at, created_at)) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $query->whereRaw('DATE(COALESCE(refunded_at, created_at)) <= ?', [$dateTo]); } $row = (array) $query->selectRaw('COALESCE(SUM(refund_paid_amount),0) AS refund_paid_amount')->first(); - return (float) ($row['refund_paid_amount'] ?? 0); } @@ -434,15 +427,14 @@ class FinancialSummaryService ->join('invoices as i', 'i.id', '=', 'du.invoice_id') ->where('i.school_year', $schoolYear); - if (! empty($dateFrom)) { + if (!empty($dateFrom)) { $query->whereRaw('DATE(COALESCE(du.used_at, du.created_at)) >= ?', [$dateFrom]); } - if (! empty($dateTo)) { + if (!empty($dateTo)) { $query->whereRaw('DATE(COALESCE(du.used_at, du.created_at)) <= ?', [$dateTo]); } $row = (array) $query->selectRaw('COALESCE(SUM(du.discount_amount),0) AS discount_amount')->first(); - return (float) ($row['discount_amount'] ?? 0); } @@ -462,14 +454,14 @@ class FinancialSummaryService $ref = (float) ($refundByInvoice[$invoiceId] ?? 0); $balance = max(0.0, round($total - $disc - $paid - $ref, 2)); - if (! isset($parentBalances[$parentId])) { + if (!isset($parentBalances[$parentId])) { $parentBalances[$parentId] = 0.0; } $parentBalances[$parentId] += $balance; } foreach ($extraByParent as $parentId => $extra) { - if (! isset($parentBalances[$parentId])) { + if (!isset($parentBalances[$parentId])) { $parentBalances[$parentId] = 0.0; } $parentBalances[$parentId] += (float) $extra; diff --git a/app/Services/Finance/FinancialUnpaidParentsService.php b/app/Services/Finance/FinancialUnpaidParentsService.php index 356f2955..fddd9a56 100644 --- a/app/Services/Finance/FinancialUnpaidParentsService.php +++ b/app/Services/Finance/FinancialUnpaidParentsService.php @@ -8,7 +8,9 @@ use Illuminate\Support\Facades\Schema; class FinancialUnpaidParentsService { - public function __construct(private FinancialSchoolYearService $schoolYears) {} + public function __construct(private FinancialSchoolYearService $schoolYears) + { + } public function getUnpaidParents(?string $schoolYear): array { @@ -74,7 +76,7 @@ class FinancialUnpaidParentsService $total = (float) ($row['total_amount'] ?? 0); $balance = max(0.0, round($total - $discSum - $paidSum - $refSum, 2)); - if (! isset($byParent[$parentId])) { + if (!isset($byParent[$parentId])) { $byParent[$parentId] = [ 'parent_id' => $parentId, 'firstname' => (string) ($row['firstname'] ?? ''), @@ -94,7 +96,7 @@ class FinancialUnpaidParentsService } $extraRows = DB::table('additional_charges as ac') - ->selectRaw('ac.parent_id, u.firstname, u.lastname, u.email, COALESCE(SUM(ac.amount), 0) AS total_extra') + ->selectRaw("ac.parent_id, u.firstname, u.lastname, u.email, COALESCE(SUM(ac.amount), 0) AS total_extra") ->leftJoin('users as u', 'u.id', '=', 'ac.parent_id') ->where('ac.school_year', $schoolYear) ->where('ac.status', '!=', 'void') @@ -117,7 +119,7 @@ class FinancialUnpaidParentsService if (abs($extra) < 0.00001) { continue; } - if (! isset($byParent[$parentId])) { + if (!isset($byParent[$parentId])) { $byParent[$parentId] = [ 'parent_id' => $parentId, 'firstname' => (string) ($row['firstname'] ?? ''), @@ -148,8 +150,8 @@ class FinancialUnpaidParentsService } } - $monthsUntil = static function (?\DateTimeImmutable $end) use ($today): int { - if (! $end) { + $monthsUntil = static function (? \DateTimeImmutable $end) use ($today): int { + if (!$end) { return 0; } $y = (int) $end->format('Y') - (int) $today->format('Y'); @@ -158,7 +160,6 @@ class FinancialUnpaidParentsService if ((int) $end->format('j') > (int) $today->format('j')) { $months += 1; } - return max(0, $months); }; @@ -194,7 +195,7 @@ class FinancialUnpaidParentsService $hasPayments = []; $paidTotals = []; $paymentCounts = []; - if (! empty($parentIds)) { + if (!empty($parentIds)) { $pRows = DB::table('payments') ->selectRaw('parent_id, SUM(paid_amount) AS total_paid, COUNT(*) AS payment_count') ->whereIn('parent_id', $parentIds) @@ -216,8 +217,7 @@ class FinancialUnpaidParentsService $results = array_map(function (array $row) use ($hasPayments, $paidTotals, $paymentCounts, $nextInstallment) { $parentId = (int) ($row['parent_id'] ?? 0); - $name = trim((string) ($row['firstname'] ?? '').' '.(string) ($row['lastname'] ?? '')); - + $name = trim((string) ($row['firstname'] ?? '') . ' ' . (string) ($row['lastname'] ?? '')); return [ 'parent_id' => $parentId, 'parent_name' => $name, diff --git a/app/Services/Finance/InstallmentPlanService.php b/app/Services/Finance/InstallmentPlanService.php index 216628aa..aa949ca9 100644 --- a/app/Services/Finance/InstallmentPlanService.php +++ b/app/Services/Finance/InstallmentPlanService.php @@ -7,33 +7,31 @@ use App\Models\InvoiceInstallmentPlan; use App\Models\PaymentInstallmentAllocation; use Carbon\Carbon; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Schema; class InstallmentPlanService { public function list(array $filters): array { $q = InvoiceInstallmentPlan::query(); - foreach (['invoice_id', 'parent_id', 'school_year', 'status'] as $field) { - if (! empty($filters[$field])) { - $q->where($field, $filters[$field]); - } + foreach (['invoice_id','parent_id','school_year','status'] as $field) { + if (!empty($filters[$field])) $q->where($field, $filters[$field]); } - - return ['rows' => $q->orderByDesc('id')->paginate((int) ($filters['per_page'] ?? 25))]; + return ['rows' => $q->orderByDesc('id')->paginate((int)($filters['per_page'] ?? 25))]; } public function createForInvoice(int $invoiceId, array $payload, ?int $actorId): array { return DB::transaction(function () use ($invoiceId, $payload, $actorId) { $invoice = DB::table('invoices')->where('id', $invoiceId)->first(); - abort_if(! $invoice, 404, 'Invoice not found.'); + abort_if(!$invoice, 404, 'Invoice not found.'); $total = (float) ($payload['total_amount'] ?? ($invoice->balance ?? $invoice->total_amount ?? 0)); $count = (int) $payload['number_of_installments']; $plan = InvoiceInstallmentPlan::query()->create([ 'invoice_id' => $invoiceId, 'parent_id' => $invoice->parent_id, 'school_year' => $invoice->school_year ?? null, - 'plan_name' => $payload['plan_name'] ?? ('Invoice #'.$invoiceId.' installment plan'), + 'plan_name' => $payload['plan_name'] ?? ('Invoice #' . $invoiceId . ' installment plan'), 'total_amount' => $total, 'number_of_installments' => $count, 'status' => 'draft', @@ -67,7 +65,6 @@ class InstallmentPlanService { $plan = InvoiceInstallmentPlan::query()->findOrFail($id)->toArray(); $plan['installments'] = InvoiceInstallment::query()->where('installment_plan_id', $id)->orderBy('sequence')->get()->toArray(); - return $plan; } @@ -76,7 +73,6 @@ class InstallmentPlanService $plan = InvoiceInstallmentPlan::query()->findOrFail($id); $plan->fill(['status' => 'active', 'approved_by' => $actorId])->save(); InvoiceInstallment::query()->where('installment_plan_id', $id)->where('status', 'pending')->update(['status' => 'due']); - return $this->show($id); } @@ -84,7 +80,6 @@ class InstallmentPlanService { InvoiceInstallmentPlan::query()->whereKey($id)->update(['status' => 'cancelled']); InvoiceInstallment::query()->where('installment_plan_id', $id)->whereNotIn('status', ['paid'])->update(['status' => 'cancelled']); - return $this->show($id); } @@ -92,16 +87,14 @@ class InstallmentPlanService { return DB::transaction(function () use ($paymentId, $payload) { $payment = DB::table('payments')->where('id', $paymentId)->first(); - abort_if(! $payment, 404, 'Payment not found.'); + abort_if(!$payment, 404, 'Payment not found.'); $allocations = $payload['installments'] ?? null; - if (! $allocations) { + if (!$allocations) { $remaining = (float) ($payment->paid_amount ?? 0); $installments = InvoiceInstallment::query()->where('invoice_id', $payment->invoice_id)->where('balance', '>', 0)->orderBy('due_date')->lockForUpdate()->get(); $allocations = []; foreach ($installments as $inst) { - if ($remaining <= 0) { - break; - } + if ($remaining <= 0) break; $amount = min($remaining, (float) $inst->balance); $allocations[] = ['installment_id' => $inst->id, 'amount' => $amount]; $remaining -= $amount; @@ -112,9 +105,7 @@ class InstallmentPlanService foreach ($allocations as $a) { $inst = InvoiceInstallment::query()->lockForUpdate()->findOrFail($a['installment_id']); $amount = min((float) $a['amount'], (float) $inst->balance); - if ($amount <= 0) { - continue; - } + if ($amount <= 0) continue; $created[] = PaymentInstallmentAllocation::query()->create([ 'payment_id' => $paymentId, 'invoice_id' => $inst->invoice_id, @@ -127,7 +118,6 @@ class InstallmentPlanService $inst->paid_at = $inst->balance <= 0 ? now() : null; $inst->save(); } - return ['allocations' => $created]; }); } @@ -136,12 +126,11 @@ class InstallmentPlanService { $q = InvoiceInstallment::query()->where('balance', '>', 0); $overdue ? $q->whereDate('due_date', '<', now()->toDateString()) : $q->whereDate('due_date', '>=', now()->toDateString()); - return ['rows' => $q->orderBy('due_date')->get()->toArray()]; } public function markOverdue(): int { - return InvoiceInstallment::query()->where('balance', '>', 0)->whereDate('due_date', '<', now()->toDateString())->whereNotIn('status', ['paid', 'cancelled', 'waived'])->update(['status' => 'overdue']); + return InvoiceInstallment::query()->where('balance', '>', 0)->whereDate('due_date', '<', now()->toDateString())->whereNotIn('status', ['paid','cancelled','waived'])->update(['status' => 'overdue']); } } diff --git a/app/Services/Finance/ParentPaymentFollowUpService.php b/app/Services/Finance/ParentPaymentFollowUpService.php index 630729bb..fc084be1 100644 --- a/app/Services/Finance/ParentPaymentFollowUpService.php +++ b/app/Services/Finance/ParentPaymentFollowUpService.php @@ -4,7 +4,6 @@ namespace App\Services\Finance; use App\Models\Configuration; use App\Models\FinanceFollowUpNote; -use Carbon\Carbon; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; @@ -36,11 +35,11 @@ class ParentPaymentFollowUpService $discounted = (float) ($discountByInvoice[$invoiceId] ?? 0); $refunded = (float) ($refundByInvoice[$invoiceId] ?? 0); $open = max(0, $total - $paid - $discounted - $refunded); - if (! $includePaid && $open <= 0) { + if (!$includePaid && $open <= 0) { continue; } - if (! isset($parents[$parentId])) { + if (!isset($parents[$parentId])) { $parents[$parentId] = [ 'parent_id' => $parentId, 'parent_name' => $invoice->parent_name ?? null, @@ -72,7 +71,7 @@ class ParentPaymentFollowUpService ]; } - $row = &$parents[$parentId]; + $row =& $parents[$parentId]; $row['invoice_count']++; $row['total_invoiced'] += $total; $row['total_paid'] += $paid; @@ -100,7 +99,7 @@ class ParentPaymentFollowUpService $row['promise_to_pay_amount'] = $note->promise_to_pay_amount !== null ? (float) $note->promise_to_pay_amount : null; $row['escalation_level'] = (int) ($note->escalation_level ?? 0); } - $row['notes_count'] = FinanceFollowUpNote::query()->where('parent_id', $parentId)->when($schoolYear, fn ($q) => $q->where('school_year', $schoolYear))->count(); + $row['notes_count'] = FinanceFollowUpNote::query()->where('parent_id', $parentId)->when($schoolYear, fn($q) => $q->where('school_year', $schoolYear))->count(); $row['days_overdue'] = $this->daysOverdue($row['oldest_unpaid_invoice_date']); $row['aging_bucket'] = $this->agingBucket($row['days_overdue']); $row['risk_flags'] = $this->riskFlags($row); @@ -108,26 +107,15 @@ class ParentPaymentFollowUpService unset($row); $rows = array_values(array_filter($parents, function (array $row) use ($filters, $minimumBalance) { - if ($row['open_balance'] < $minimumBalance) { - return false; - } - if (! empty($filters['aging_bucket']) && $row['aging_bucket'] !== $filters['aging_bucket']) { - return false; - } - if (! empty($filters['follow_up_status']) && $row['follow_up_status'] !== $filters['follow_up_status']) { - return false; - } - if (! empty($filters['next_follow_up_due_before']) && (empty($row['next_follow_up_date']) || strtotime($row['next_follow_up_date']) > strtotime($filters['next_follow_up_due_before']))) { - return false; - } - if (! empty($filters['promise_to_pay_due_before']) && (empty($row['promise_to_pay_date']) || strtotime($row['promise_to_pay_date']) > strtotime($filters['promise_to_pay_due_before']))) { - return false; - } - + if ($row['open_balance'] < $minimumBalance) return false; + if (!empty($filters['aging_bucket']) && $row['aging_bucket'] !== $filters['aging_bucket']) return false; + if (!empty($filters['follow_up_status']) && $row['follow_up_status'] !== $filters['follow_up_status']) return false; + if (!empty($filters['next_follow_up_due_before']) && (empty($row['next_follow_up_date']) || strtotime($row['next_follow_up_date']) > strtotime($filters['next_follow_up_due_before']))) return false; + if (!empty($filters['promise_to_pay_due_before']) && (empty($row['promise_to_pay_date']) || strtotime($row['promise_to_pay_date']) > strtotime($filters['promise_to_pay_due_before']))) return false; return true; })); - usort($rows, fn ($a, $b) => [$b['open_balance'], $b['days_overdue']] <=> [$a['open_balance'], $a['days_overdue']]); + usort($rows, fn($a, $b) => [$b['open_balance'], $b['days_overdue']] <=> [$a['open_balance'], $a['days_overdue']]); return ['schoolYear' => $schoolYear, 'generatedAt' => now()->toISOString(), 'results' => $rows]; } @@ -153,78 +141,56 @@ class ParentPaymentFollowUpService public function csvRows(array $report): array { - $rows = [['Parent ID', 'Parent', 'Email', 'Phone', 'Students', 'School Year', 'Invoices', 'Open Invoices', 'Total Invoiced', 'Total Paid', 'Open Balance', 'Oldest Unpaid', 'Days Overdue', 'Aging', 'Status', 'Next Follow-Up', 'Promise Date', 'Promise Amount', 'Risk Flags']]; + $rows = [['Parent ID','Parent','Email','Phone','Students','School Year','Invoices','Open Invoices','Total Invoiced','Total Paid','Open Balance','Oldest Unpaid','Days Overdue','Aging','Status','Next Follow-Up','Promise Date','Promise Amount','Risk Flags']]; foreach ($report['results'] as $r) { $rows[] = [ $r['parent_id'], $r['parent_name'], $r['parent_email'], $r['parent_phone'], implode('; ', $r['student_names'] ?? []), $r['school_year'], $r['invoice_count'], $r['open_invoice_count'], $r['total_invoiced'], $r['total_paid'], $r['open_balance'], $r['oldest_unpaid_invoice_date'], $r['days_overdue'], $r['aging_bucket'], $r['follow_up_status'], $r['next_follow_up_date'], $r['promise_to_pay_date'], $r['promise_to_pay_amount'], implode('; ', $r['risk_flags'] ?? []), ]; } - return $rows; } private function invoiceRows(string $schoolYear, array $filters) { $q = DB::table('invoices')->where('invoices.school_year', $schoolYear); - if (! empty($filters['parent_id'])) { - $q->where('invoices.parent_id', $filters['parent_id']); - } - if (! empty($filters['date_from'])) { - $q->whereDate('invoices.created_at', '>=', $filters['date_from']); - } - if (! empty($filters['date_to'])) { - $q->whereDate('invoices.created_at', '<=', $filters['date_to']); - } + if (!empty($filters['parent_id'])) $q->where('invoices.parent_id', $filters['parent_id']); + if (!empty($filters['date_from'])) $q->whereDate('invoices.created_at', '>=', $filters['date_from']); + if (!empty($filters['date_to'])) $q->whereDate('invoices.created_at', '<=', $filters['date_to']); if (Schema::hasTable('users')) { $name = $this->nameExpression('users'); $q->leftJoin('users', 'users.id', '=', 'invoices.parent_id') - ->addSelect('invoices.*') - ->addSelect(DB::raw($name.' as parent_name')) - ->addSelect('users.email as parent_email'); - if (Schema::hasColumn('users', 'phone')) { - $q->addSelect('users.phone as parent_phone'); - } else { - $q->addSelect(DB::raw('NULL as parent_phone')); - } + ->addSelect('invoices.*') + ->addSelect(DB::raw($name . ' as parent_name')) + ->addSelect('users.email as parent_email'); + if (Schema::hasColumn('users', 'phone')) $q->addSelect('users.phone as parent_phone'); + else $q->addSelect(DB::raw('NULL as parent_phone')); } else { $q->select('invoices.*', DB::raw('NULL as parent_name'), DB::raw('NULL as parent_email'), DB::raw('NULL as parent_phone')); } - return $q->get(); } private function paymentTotalsByInvoice(string $schoolYear): array { - if (! Schema::hasTable('payments')) { - return []; - } - + if (!Schema::hasTable('payments')) return []; return DB::table('payments')->select('invoice_id', DB::raw('COALESCE(SUM(paid_amount),0) total'), DB::raw('MAX(payment_date) last_payment_date')) - ->where('school_year', $schoolYear)->whereNotIn('status', ['void', 'voided', 'failed', 'cancelled', 'canceled', 'reversed']) - ->groupBy('invoice_id')->pluck('total', 'invoice_id')->map(fn ($v) => (float) $v)->all(); + ->where('school_year', $schoolYear)->whereNotIn('status', ['void','voided','failed','cancelled','canceled','reversed']) + ->groupBy('invoice_id')->pluck('total', 'invoice_id')->map(fn($v) => (float) $v)->all(); } private function discountTotalsByInvoice(): array { - if (! Schema::hasTable('discount_usages')) { - return []; - } + if (!Schema::hasTable('discount_usages')) return []; $col = Schema::hasColumn('discount_usages', 'discount_amount') ? 'discount_amount' : 'amount'; - - return DB::table('discount_usages')->select('invoice_id', DB::raw('COALESCE(SUM('.$col.'),0) total'))->groupBy('invoice_id')->pluck('total', 'invoice_id')->map(fn ($v) => (float) $v)->all(); + return DB::table('discount_usages')->select('invoice_id', DB::raw('COALESCE(SUM('.$col.'),0) total'))->groupBy('invoice_id')->pluck('total','invoice_id')->map(fn($v)=>(float)$v)->all(); } private function refundTotalsByInvoice(): array { - if (! Schema::hasTable('refunds')) { - return []; - } + if (!Schema::hasTable('refunds')) return []; $col = Schema::hasColumn('refunds', 'refund_amount') ? 'refund_amount' : (Schema::hasColumn('refunds', 'amount') ? 'amount' : null); - if (! $col) { - return []; - } - - return DB::table('refunds')->select('invoice_id', DB::raw('COALESCE(SUM('.$col.'),0) total'))->whereNotIn('status', ['void', 'voided', 'cancelled', 'canceled'])->groupBy('invoice_id')->pluck('total', 'invoice_id')->map(fn ($v) => (float) $v)->all(); + if (!$col) return []; + return DB::table('refunds')->select('invoice_id', DB::raw('COALESCE(SUM('.$col.'),0) total'))->whereNotIn('status', ['void','voided','cancelled','canceled'])->groupBy('invoice_id')->pluck('total','invoice_id')->map(fn($v)=>(float)$v)->all(); } private function latestNotesByParent(string $schoolYear): array @@ -234,66 +200,40 @@ class ParentPaymentFollowUpService private function studentsByParent(): array { - if (! Schema::hasTable('students') || ! Schema::hasColumn('students', 'parent_id')) { - return []; - } + if (!Schema::hasTable('students') || !Schema::hasColumn('students', 'parent_id')) return []; $name = $this->nameExpression('students'); - - return DB::table('students')->select('parent_id', DB::raw($name.' as student_name'))->whereNotNull('parent_id')->get()->groupBy('parent_id')->map(fn ($rows) => $rows->pluck('student_name')->filter()->values()->all())->all(); + return DB::table('students')->select('parent_id', DB::raw($name.' as student_name'))->whereNotNull('parent_id')->get()->groupBy('parent_id')->map(fn($rows) => $rows->pluck('student_name')->filter()->values()->all())->all(); } private function nameExpression(string $table): string { - if (Schema::hasColumn($table, 'name')) { - return $table.'.name'; - } - if (Schema::hasColumn($table, 'full_name')) { - return $table.'.full_name'; - } + if (Schema::hasColumn($table, 'name')) return $table.'.name'; + if (Schema::hasColumn($table, 'full_name')) return $table.'.full_name'; $driver = DB::connection()->getDriverName(); $concat = $driver === 'sqlite' ? '%s || \' \' || %s' : "CONCAT(%s, ' ', %s)"; - if (Schema::hasColumn($table, 'firstname') && Schema::hasColumn($table, 'lastname')) { - return sprintf($concat, $table.'.firstname', $table.'.lastname'); - } - if (Schema::hasColumn($table, 'first_name') && Schema::hasColumn($table, 'last_name')) { - return sprintf($concat, $table.'.first_name', $table.'.last_name'); - } - + if (Schema::hasColumn($table, 'firstname') && Schema::hasColumn($table, 'lastname')) return sprintf($concat, $table.'.firstname', $table.'.lastname'); + if (Schema::hasColumn($table, 'first_name') && Schema::hasColumn($table, 'last_name')) return sprintf($concat, $table.'.first_name', $table.'.last_name'); return "CAST($table.id AS CHAR)"; } private function daysOverdue(?string $date): int { - if (! $date) { - return 0; - } - - return max(0, now()->startOfDay()->diffInDays(Carbon::parse($date)->startOfDay(), false) * -1); + if (!$date) return 0; + return max(0, now()->startOfDay()->diffInDays(\Carbon\Carbon::parse($date)->startOfDay(), false) * -1); } private function agingBucket(int $days): string { - return match (true) { - $days <= 0 => 'current', $days <= 30 => '1-30 days overdue', $days <= 60 => '31-60 days overdue', $days <= 90 => '61-90 days overdue', default => '90+ days overdue' - }; + return match (true) { $days <= 0 => 'current', $days <= 30 => '1-30 days overdue', $days <= 60 => '31-60 days overdue', $days <= 90 => '61-90 days overdue', default => '90+ days overdue' }; } private function riskFlags(array $row): array { $flags = []; - if ($row['days_overdue'] > 90) { - $flags[] = '90+ days overdue'; - } - if ($row['open_balance'] > 1000) { - $flags[] = 'high balance'; - } - if ($row['promise_to_pay_date'] && strtotime($row['promise_to_pay_date']) < strtotime(date('Y-m-d'))) { - $flags[] = 'missed promise-to-pay'; - } - if (! $row['parent_email'] && ! $row['parent_phone']) { - $flags[] = 'missing contact info'; - } - + if ($row['days_overdue'] > 90) $flags[] = '90+ days overdue'; + if ($row['open_balance'] > 1000) $flags[] = 'high balance'; + if ($row['promise_to_pay_date'] && strtotime($row['promise_to_pay_date']) < strtotime(date('Y-m-d'))) $flags[] = 'missed promise-to-pay'; + if (!$row['parent_email'] && !$row['parent_phone']) $flags[] = 'missing contact info'; return $flags; } } diff --git a/app/Services/Finance/PriorYearBalanceCarryforwardService.php b/app/Services/Finance/PriorYearBalanceCarryforwardService.php index e9ead37f..66b4a53b 100644 --- a/app/Services/Finance/PriorYearBalanceCarryforwardService.php +++ b/app/Services/Finance/PriorYearBalanceCarryforwardService.php @@ -20,20 +20,16 @@ class PriorYearBalanceCarryforwardService $refunds = $this->refundTotals(); $q = DB::table('invoices')->where('school_year', $from); - if ($parentId) { - $q->where('parent_id', $parentId); - } + if ($parentId) $q->where('parent_id', $parentId); $invoices = $q->get(); $byParent = []; foreach ($invoices as $invoice) { $invoiceId = (int) $invoice->id; $balance = max(0, (float) ($invoice->total_amount ?? 0) - (float) ($payments[$invoiceId] ?? 0) - (float) ($discounts[$invoiceId] ?? 0) - (float) ($refunds[$invoiceId] ?? 0)); - if ($balance <= 0) { - continue; - } + if ($balance <= 0) continue; $pid = (int) $invoice->parent_id; - if (! isset($byParent[$pid])) { + if (!isset($byParent[$pid])) { $existing = FinanceBalanceCarryforward::query()->where('parent_id', $pid)->where('from_school_year', $from)->where('to_school_year', $to)->first(); $byParent[$pid] = [ 'parent_id' => $pid, @@ -45,17 +41,15 @@ class PriorYearBalanceCarryforwardService 'existing_carryforward_id' => $existing?->id, 'warnings' => [], ]; - if ($existing) { - $byParent[$pid]['warnings'][] = 'source invoice already carried forward'; - } + if ($existing) $byParent[$pid]['warnings'][] = 'source invoice already carried forward'; } $byParent[$pid]['source_invoice_ids'][] = $invoiceId; $byParent[$pid]['source_balance_amount'] += $balance; $byParent[$pid]['proposed_carryforward_amount'] += $balance; } - $rows = array_values(array_filter($byParent, fn ($r) => $r['source_balance_amount'] >= $minimum)); - usort($rows, fn ($a, $b) => $b['source_balance_amount'] <=> $a['source_balance_amount']); + $rows = array_values(array_filter($byParent, fn($r) => $r['source_balance_amount'] >= $minimum)); + usort($rows, fn($a, $b) => $b['source_balance_amount'] <=> $a['source_balance_amount']); return ['fromSchoolYear' => $from, 'toSchoolYear' => $to, 'generatedAt' => now()->toISOString(), 'rows' => $rows]; } @@ -65,9 +59,7 @@ class PriorYearBalanceCarryforwardService $preview = $this->preview($filters); $created = []; foreach ($preview['rows'] as $row) { - if (! empty($row['existing_carryforward_id'])) { - continue; - } + if (!empty($row['existing_carryforward_id'])) continue; $created[] = FinanceBalanceCarryforward::query()->create([ 'parent_id' => $row['parent_id'], 'from_school_year' => $row['from_school_year'], @@ -82,7 +74,6 @@ class PriorYearBalanceCarryforwardService 'metadata_json' => ['warnings' => $row['warnings']], ])->toArray(); } - return ['created' => $created, 'skipped' => count($preview['rows']) - count($created)]; } @@ -90,7 +81,6 @@ class PriorYearBalanceCarryforwardService { $cf = FinanceBalanceCarryforward::query()->findOrFail($id); $cf->fill(['status' => 'approved', 'approved_by' => $actorId, 'approved_at' => now()])->save(); - return $cf->fresh()->toArray(); } @@ -104,7 +94,6 @@ class PriorYearBalanceCarryforwardService $cf->reason = $reason ?: $cf->reason; $cf->approved_by = $cf->approved_by ?: $actorId; $cf->save(); - return $cf->fresh()->toArray(); } @@ -115,7 +104,6 @@ class PriorYearBalanceCarryforwardService $cf->remaining_amount = max(0, (float) $cf->carryforward_amount - (float) $cf->waived_amount + $amount); $cf->reason = $reason ?: $cf->reason; $cf->save(); - return $cf->fresh()->toArray(); } @@ -123,7 +111,7 @@ class PriorYearBalanceCarryforwardService { return DB::transaction(function () use ($id, $actorId) { $cf = FinanceBalanceCarryforward::query()->lockForUpdate()->findOrFail($id); - if (! in_array($cf->status, ['approved', 'draft', 'pending_review'], true)) { + if (!in_array($cf->status, ['approved','draft','pending_review'], true)) { return $cf->toArray() + ['warning' => 'Carryforward is not in a postable status.']; } @@ -132,14 +120,14 @@ class PriorYearBalanceCarryforwardService if (Schema::hasTable('invoices')) { $invoiceId = DB::table('invoices')->insertGetId([ 'parent_id' => $cf->parent_id, - 'invoice_number' => 'CF-'.$cf->to_school_year.'-'.$cf->id, + 'invoice_number' => 'CF-' . $cf->to_school_year . '-' . $cf->id, 'total_amount' => $amount, 'balance' => $amount, 'paid_amount' => 0, 'school_year' => $cf->to_school_year, 'issue_date' => now()->toDateString(), 'status' => $amount > 0 ? 'unpaid' : 'paid', - 'description' => 'Previous year balance from '.$cf->from_school_year, + 'description' => 'Previous year balance from ' . $cf->from_school_year, 'created_at' => now(), 'updated_at' => now(), 'updated_by' => $actorId, @@ -149,7 +137,6 @@ class PriorYearBalanceCarryforwardService $cf->status = 'posted_to_new_year'; $cf->remaining_amount = $amount; $cf->save(); - return $cf->fresh()->toArray(); }); } @@ -157,54 +144,37 @@ class PriorYearBalanceCarryforwardService public function report(array $filters): array { $q = FinanceBalanceCarryforward::query(); - foreach (['from_school_year', 'to_school_year', 'parent_id', 'status'] as $field) { - if (! empty($filters[$field])) { - $q->where($field, $filters[$field]); - } + foreach (['from_school_year','to_school_year','parent_id','status'] as $field) { + if (!empty($filters[$field])) $q->where($field, $filters[$field]); } - return ['generatedAt' => now()->toISOString(), 'rows' => $q->orderByDesc('remaining_amount')->get()->toArray()]; } public function csvRows(array $report): array { - $rows = [['ID', 'Parent ID', 'From Year', 'To Year', 'Source Invoices', 'Source Balance', 'Carryforward', 'Waived', 'Adjusted', 'Remaining', 'Status', 'Posted Invoice']]; + $rows = [['ID','Parent ID','From Year','To Year','Source Invoices','Source Balance','Carryforward','Waived','Adjusted','Remaining','Status','Posted Invoice']]; foreach ($report['rows'] as $r) { - $rows[] = [$r['id'], $r['parent_id'], $r['from_school_year'], $r['to_school_year'], json_encode($r['source_invoice_ids_json'] ?? []), $r['source_balance_amount'], $r['carryforward_amount'], $r['waived_amount'], $r['adjusted_amount'], $r['remaining_amount'], $r['status'], $r['posted_invoice_id'] ?? null]; + $rows[] = [$r['id'],$r['parent_id'],$r['from_school_year'],$r['to_school_year'],json_encode($r['source_invoice_ids_json'] ?? []),$r['source_balance_amount'],$r['carryforward_amount'],$r['waived_amount'],$r['adjusted_amount'],$r['remaining_amount'],$r['status'],$r['posted_invoice_id'] ?? null]; } - return $rows; } private function paymentTotals(string $schoolYear): array { - if (! Schema::hasTable('payments')) { - return []; - } - - return DB::table('payments')->where('school_year', $schoolYear)->whereNotIn('status', ['void', 'voided', 'failed', 'cancelled', 'canceled', 'reversed'])->select('invoice_id', DB::raw('COALESCE(SUM(paid_amount),0) total'))->groupBy('invoice_id')->pluck('total', 'invoice_id')->map(fn ($v) => (float) $v)->all(); + if (!Schema::hasTable('payments')) return []; + return DB::table('payments')->where('school_year', $schoolYear)->whereNotIn('status', ['void','voided','failed','cancelled','canceled','reversed'])->select('invoice_id', DB::raw('COALESCE(SUM(paid_amount),0) total'))->groupBy('invoice_id')->pluck('total','invoice_id')->map(fn($v)=>(float)$v)->all(); } - private function discountTotals(): array { - if (! Schema::hasTable('discount_usages')) { - return []; - } - $col = Schema::hasColumn('discount_usages', 'discount_amount') ? 'discount_amount' : 'amount'; - - return DB::table('discount_usages')->select('invoice_id', DB::raw('COALESCE(SUM('.$col.'),0) total'))->groupBy('invoice_id')->pluck('total', 'invoice_id')->map(fn ($v) => (float) $v)->all(); + if (!Schema::hasTable('discount_usages')) return []; + $col = Schema::hasColumn('discount_usages','discount_amount') ? 'discount_amount' : 'amount'; + return DB::table('discount_usages')->select('invoice_id', DB::raw('COALESCE(SUM('.$col.'),0) total'))->groupBy('invoice_id')->pluck('total','invoice_id')->map(fn($v)=>(float)$v)->all(); } - private function refundTotals(): array { - if (! Schema::hasTable('refunds')) { - return []; - } - $col = Schema::hasColumn('refunds', 'refund_amount') ? 'refund_amount' : (Schema::hasColumn('refunds', 'amount') ? 'amount' : null); - if (! $col) { - return []; - } - - return DB::table('refunds')->whereNotIn('status', ['void', 'voided', 'cancelled', 'canceled'])->select('invoice_id', DB::raw('COALESCE(SUM('.$col.'),0) total'))->groupBy('invoice_id')->pluck('total', 'invoice_id')->map(fn ($v) => (float) $v)->all(); + if (!Schema::hasTable('refunds')) return []; + $col = Schema::hasColumn('refunds','refund_amount') ? 'refund_amount' : (Schema::hasColumn('refunds','amount') ? 'amount' : null); + if (!$col) return []; + return DB::table('refunds')->whereNotIn('status', ['void','voided','cancelled','canceled'])->select('invoice_id', DB::raw('COALESCE(SUM('.$col.'),0) total'))->groupBy('invoice_id')->pluck('total','invoice_id')->map(fn($v)=>(float)$v)->all(); } } diff --git a/app/Services/Finance/StakeholderFinancialAnalysisService.php b/app/Services/Finance/StakeholderFinancialAnalysisService.php index 98f9c754..ab9415ef 100644 --- a/app/Services/Finance/StakeholderFinancialAnalysisService.php +++ b/app/Services/Finance/StakeholderFinancialAnalysisService.php @@ -3,7 +3,6 @@ namespace App\Services\Finance; use App\Models\Configuration; -use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; @@ -22,7 +21,7 @@ class StakeholderFinancialAnalysisService $current = $this->periodMetrics($schoolYear, $rangeFrom, $rangeTo); $comparison = null; - if (! empty($compareSchoolYear)) { + if (!empty($compareSchoolYear)) { [$compareFrom, $compareTo] = $this->resolveDateRange($compareSchoolYear, null, null); $comparison = $this->periodMetrics($compareSchoolYear, $compareFrom, $compareTo); } @@ -71,7 +70,6 @@ class StakeholderFinancialAnalysisService foreach ($value as $bucket => $amount) { $rows[] = ['Receivables Aging', $bucket, $amount]; } - continue; } $rows[] = ['Receivables', $key, is_scalar($value) ? $value : json_encode($value)]; @@ -83,15 +81,14 @@ class StakeholderFinancialAnalysisService $rows[] = ['Payment Method Mix', $method, $amount]; } foreach (($analysis['monthlyTrend'] ?? []) as $month => $data) { - $rows[] = ['Monthly Trend', $month.' charges', $data['charges'] ?? 0]; - $rows[] = ['Monthly Trend', $month.' collections', $data['collections'] ?? 0]; - $rows[] = ['Monthly Trend', $month.' expenses', $data['expenses'] ?? 0]; - $rows[] = ['Monthly Trend', $month.' netCash', $data['netCash'] ?? 0]; + $rows[] = ['Monthly Trend', $month . ' charges', $data['charges'] ?? 0]; + $rows[] = ['Monthly Trend', $month . ' collections', $data['collections'] ?? 0]; + $rows[] = ['Monthly Trend', $month . ' expenses', $data['expenses'] ?? 0]; + $rows[] = ['Monthly Trend', $month . ' netCash', $data['netCash'] ?? 0]; } foreach (($analysis['riskFlags'] ?? []) as $flag) { $rows[] = ['Risk Flag', $flag['level'] ?? '', $flag['message'] ?? '']; } - return $rows; } @@ -172,19 +169,18 @@ class StakeholderFinancialAnalysisService private function invoiceTotals(string $schoolYear, ?string $dateFrom, ?string $dateTo): array { - if (! Schema::hasTable('invoices')) { + if (!Schema::hasTable('invoices')) { return ['total' => 0.0, 'count' => 0]; } $q = DB::table('invoices')->where('school_year', $schoolYear); $this->applyDateRange($q, $this->dateColumn('invoices', ['issue_date', 'created_at']), $dateFrom, $dateTo); $row = (array) $q->selectRaw('COALESCE(SUM(total_amount),0) as total, COUNT(*) as count')->first(); - return ['total' => (float) ($row['total'] ?? 0), 'count' => (int) ($row['count'] ?? 0)]; } private function paymentTotals(string $schoolYear, ?string $dateFrom, ?string $dateTo): array { - if (! Schema::hasTable('payments')) { + if (!Schema::hasTable('payments')) { return ['total' => 0.0, 'familyCount' => 0, 'byMethod' => []]; } $base = DB::table('payments')->where('school_year', $schoolYear); @@ -202,13 +198,12 @@ class StakeholderFinancialAnalysisService $arr = (array) $row; $byMethod[(string) ($arr['method'] ?? 'unknown')] = (float) ($arr['total'] ?? 0); } - return ['total' => $total, 'familyCount' => $familyCount, 'byMethod' => $byMethod]; } private function refundTotals(string $schoolYear, ?string $dateFrom, ?string $dateTo): array { - if (! Schema::hasTable('refunds')) { + if (!Schema::hasTable('refunds')) { return ['total' => 0.0]; } $q = DB::table('refunds')->where('school_year', $schoolYear); @@ -217,14 +212,13 @@ class StakeholderFinancialAnalysisService } $this->applyDateRange($q, $this->dateColumn('refunds', ['refunded_at', 'approved_at', 'created_at']), $dateFrom, $dateTo); $amountColumn = Schema::hasColumn('refunds', 'refund_paid_amount') ? 'refund_paid_amount' : 'refund_amount'; - $row = (array) $q->selectRaw('COALESCE(SUM('.$amountColumn.'),0) as total')->first(); - + $row = (array) $q->selectRaw('COALESCE(SUM(' . $amountColumn . '),0) as total')->first(); return ['total' => (float) ($row['total'] ?? 0)]; } private function discountTotals(string $schoolYear, ?string $dateFrom, ?string $dateTo): array { - if (! Schema::hasTable('discount_usages')) { + if (!Schema::hasTable('discount_usages')) { return ['total' => 0.0]; } $q = DB::table('discount_usages as du'); @@ -234,21 +228,19 @@ class StakeholderFinancialAnalysisService $this->excludeStatuses($q, 'discount_usages', $this->excludedChargeStatuses, 'du.status'); $this->applyDateRange($q, Schema::hasColumn('discount_usages', 'created_at') ? 'du.created_at' : null, $dateFrom, $dateTo); $amountColumn = Schema::hasColumn('discount_usages', 'discount_amount') ? 'discount_amount' : 'amount'; - $row = (array) $q->selectRaw('COALESCE(SUM(du.'.$amountColumn.'),0) as total')->first(); - + $row = (array) $q->selectRaw('COALESCE(SUM(du.' . $amountColumn . '),0) as total')->first(); return ['total' => (float) ($row['total'] ?? 0)]; } private function additionalChargeTotals(string $schoolYear, ?string $dateFrom, ?string $dateTo): array { - if (! Schema::hasTable('additional_charges')) { + if (!Schema::hasTable('additional_charges')) { return ['total' => 0.0]; } $q = DB::table('additional_charges')->where('school_year', $schoolYear); $this->excludeStatuses($q, 'additional_charges', $this->excludedChargeStatuses); $this->applyDateRange($q, $this->dateColumn('additional_charges', ['due_date', 'created_at']), $dateFrom, $dateTo); $row = (array) $q->selectRaw('COALESCE(SUM(amount),0) as total')->first(); - return ['total' => (float) ($row['total'] ?? 0)]; } @@ -268,21 +260,20 @@ class StakeholderFinancialAnalysisService return ['total' => 0.0]; } $this->applyDateRange($q, $this->dateColumn($table, ['charge_date', 'created_at']), $dateFrom, $dateTo); - $row = (array) $q->selectRaw('COALESCE(SUM('.$amountColumn.'),0) as total')->first(); - + $row = (array) $q->selectRaw('COALESCE(SUM(' . $amountColumn . '),0) as total')->first(); return ['total' => (float) ($row['total'] ?? 0)]; } private function expenseTotals(string $schoolYear, ?string $dateFrom, ?string $dateTo): array { - if (! Schema::hasTable('expenses')) { + if (!Schema::hasTable('expenses')) { return ['total' => 0.0, 'byCategory' => []]; } $q = DB::table('expenses')->where('school_year', $schoolYear); $this->excludeStatuses($q, 'expenses', ['void', 'voided', 'rejected', 'cancelled', 'canceled']); $this->applyDateRange($q, $this->dateColumn('expenses', ['expense_date', 'date', 'created_at']), $dateFrom, $dateTo); $amountColumn = Schema::hasColumn('expenses', 'amount') ? 'amount' : 'total_amount'; - $total = (float) ((array) (clone $q)->selectRaw('COALESCE(SUM('.$amountColumn.'),0) as total')->first())['total']; + $total = (float) ((array) (clone $q)->selectRaw('COALESCE(SUM(' . $amountColumn . '),0) as total')->first())['total']; $categoryColumn = Schema::hasColumn('expenses', 'category') ? 'category' : (Schema::hasColumn('expenses', 'expense_category') ? 'expense_category' : null); $byCategory = []; if ($categoryColumn) { @@ -291,13 +282,12 @@ class StakeholderFinancialAnalysisService $byCategory[(string) ($arr['category'] ?? 'uncategorized')] = (float) ($arr['total'] ?? 0); } } - return ['total' => $total, 'byCategory' => $byCategory]; } private function reimbursementTotals(string $schoolYear, ?string $dateFrom, ?string $dateTo): array { - if (! Schema::hasTable('reimbursements')) { + if (!Schema::hasTable('reimbursements')) { return ['total' => 0.0]; } $q = DB::table('reimbursements')->where('school_year', $schoolYear); @@ -306,8 +296,7 @@ class StakeholderFinancialAnalysisService } $this->applyDateRange($q, $this->dateColumn('reimbursements', ['reimbursed_at', 'created_at']), $dateFrom, $dateTo); $amountColumn = Schema::hasColumn('reimbursements', 'amount') ? 'amount' : (Schema::hasColumn('reimbursements', 'total_amount') ? 'total_amount' : 'reimbursement_amount'); - $row = (array) $q->selectRaw('COALESCE(SUM('.$amountColumn.'),0) as total')->first(); - + $row = (array) $q->selectRaw('COALESCE(SUM(' . $amountColumn . '),0) as total')->first(); return ['total' => (float) ($row['total'] ?? 0)]; } @@ -315,7 +304,7 @@ class StakeholderFinancialAnalysisService { $buckets = ['current' => 0.0, '1_30_days' => 0.0, '31_60_days' => 0.0, '61_90_days' => 0.0, 'over_90_days' => 0.0]; $largest = []; - if (! Schema::hasTable('invoices')) { + if (!Schema::hasTable('invoices')) { return ['total' => 0.0, 'buckets' => $buckets, 'largestOpenInvoices' => []]; } $q = DB::table('invoices')->where('school_year', $schoolYear); @@ -338,8 +327,8 @@ class StakeholderFinancialAnalysisService $dueRaw = $arr['due_date'] ?? $arr['created_at'] ?? null; $days = 0; try { - if (! empty($dueRaw)) { - $days = max(0, (int) Carbon::parse($dueRaw)->startOfDay()->diffInDays($today, false)); + if (!empty($dueRaw)) { + $days = max(0, (int) \Illuminate\Support\Carbon::parse($dueRaw)->startOfDay()->diffInDays($today, false)); } } catch (\Throwable $e) { $days = 0; @@ -355,7 +344,6 @@ class StakeholderFinancialAnalysisService ]; } usort($largest, fn ($a, $b) => (float) $b['balance'] <=> (float) $a['balance']); - return ['total' => $total, 'buckets' => $buckets, 'largestOpenInvoices' => array_slice($largest, 0, 10)]; } @@ -379,13 +367,12 @@ class StakeholderFinancialAnalysisService ]; } ksort($months); - return $months; } private function monthlySum(string $table, string $amountColumn, string $schoolYear, ?string $dateColumn, ?string $dateFrom, ?string $dateTo, array $excludedStatuses = []): array { - if (! Schema::hasTable($table) || ! Schema::hasColumn($table, $amountColumn) || $dateColumn === null) { + if (!Schema::hasTable($table) || !Schema::hasColumn($table, $amountColumn) || $dateColumn === null) { return []; } $q = DB::table($table); @@ -398,18 +385,17 @@ class StakeholderFinancialAnalysisService $monthExpr = $driver === 'sqlite' ? "strftime('%Y-%m', $dateColumn)" : "DATE_FORMAT($dateColumn, '%Y-%m')"; - $rows = $q->selectRaw($monthExpr.' as month, COALESCE(SUM('.$amountColumn.'),0) as total') + $rows = $q->selectRaw($monthExpr . ' as month, COALESCE(SUM(' . $amountColumn . '),0) as total') ->groupBy('month') ->orderBy('month') ->get(); $out = []; foreach ($rows as $row) { $arr = (array) $row; - if (! empty($arr['month'])) { + if (!empty($arr['month'])) { $out[(string) $arr['month']] = (float) ($arr['total'] ?? 0); } } - return $out; } @@ -424,7 +410,6 @@ class StakeholderFinancialAnalysisService if ($comparison) { $summary['comparison'] = $this->deltas($current['keyMetrics'], $comparison['keyMetrics']); } - return $summary; } @@ -446,7 +431,6 @@ class StakeholderFinancialAnalysisService if (empty($flags)) { $flags[] = ['level' => 'ok', 'message' => 'No automatic risk flags were triggered for the selected period.']; } - return $flags; } @@ -464,17 +448,15 @@ class StakeholderFinancialAnalysisService 'changePct' => $prev != 0.0 ? $this->percent((($cur - $prev) / abs($prev)) * 100) : null, ]; } - return $out; } private function resolveDateRange(string $schoolYear, ?string $dateFrom, ?string $dateTo): array { - if ((! $dateFrom || ! $dateTo) && preg_match('/^(\d{4})\D?(\d{4})$/', $schoolYear, $m)) { - $dateFrom = $dateFrom ?: $m[1].'-01-01'; - $dateTo = $dateTo ?: $m[2].'-12-31'; + if ((!$dateFrom || !$dateTo) && preg_match('/^(\d{4})\D?(\d{4})$/', $schoolYear, $m)) { + $dateFrom = $dateFrom ?: $m[1] . '-01-01'; + $dateTo = $dateTo ?: $m[2] . '-12-31'; } - return [$dateFrom, $dateTo]; } @@ -483,17 +465,17 @@ class StakeholderFinancialAnalysisService if ($column === null) { return; } - if (! empty($dateFrom)) { - $query->whereRaw('DATE('.$column.') >= ?', [$dateFrom]); + if (!empty($dateFrom)) { + $query->whereRaw('DATE(' . $column . ') >= ?', [$dateFrom]); } - if (! empty($dateTo)) { - $query->whereRaw('DATE('.$column.') <= ?', [$dateTo]); + if (!empty($dateTo)) { + $query->whereRaw('DATE(' . $column . ') <= ?', [$dateTo]); } } private function excludeStatuses($query, string $table, array $statuses, ?string $qualifiedColumn = null): void { - if (empty($statuses) || ! Schema::hasColumn($table, 'status')) { + if (empty($statuses) || !Schema::hasColumn($table, 'status')) { return; } $column = $qualifiedColumn ?: 'status'; @@ -504,7 +486,7 @@ class StakeholderFinancialAnalysisService private function dateColumn(string $table, array $candidates): ?string { - if (! Schema::hasTable($table)) { + if (!Schema::hasTable($table)) { return null; } foreach ($candidates as $column) { @@ -512,7 +494,6 @@ class StakeholderFinancialAnalysisService return $column; } } - return null; } diff --git a/app/Services/Frontend/ContactSubmissionService.php b/app/Services/Frontend/ContactSubmissionService.php index a0ee0228..71ce244f 100644 --- a/app/Services/Frontend/ContactSubmissionService.php +++ b/app/Services/Frontend/ContactSubmissionService.php @@ -2,8 +2,8 @@ namespace App\Services\Frontend; -use App\Models\Configuration; use App\Models\ContactUs; +use App\Models\Configuration; use App\Services\Email\EmailDispatchService; use App\Services\System\GlobalConfigService; use Illuminate\Support\Facades\Log; @@ -13,7 +13,8 @@ class ContactSubmissionService public function __construct( private EmailDispatchService $emailService, private GlobalConfigService $configService - ) {} + ) { + } public function submit(array $payload): array { @@ -35,20 +36,20 @@ class ContactSubmissionService 'school_year' => $schoolYear ?: '2025-2026', ]); } catch (\Throwable $e) { - Log::error('Contact submission save failed: '.$e->getMessage()); + Log::error('Contact submission save failed: ' . $e->getMessage()); } $recipient = Configuration::getConfig('administrator_email') ?: (string) config('mail.from.address', '') ?: 'alrahma.isgl@gmail.com'; - $htmlMessage = nl2br('You have received a new message from '.$email.":\n\n".$message); + $htmlMessage = nl2br('You have received a new message from ' . $email . ":\n\n" . $message); $emailSent = false; - if (! app()->runningUnitTests()) { + if (!app()->runningUnitTests()) { $emailSent = $this->emailService->send($recipient, $subject, $htmlMessage, null, $email, $email); - if (! $emailSent) { - Log::error('Contact submission email failed for '.$email); + if (!$emailSent) { + Log::error('Contact submission email failed for ' . $email); } } diff --git a/app/Services/Frontend/LandingPageParentDashboardService.php b/app/Services/Frontend/LandingPageParentDashboardService.php index 27e39fef..67aee08d 100644 --- a/app/Services/Frontend/LandingPageParentDashboardService.php +++ b/app/Services/Frontend/LandingPageParentDashboardService.php @@ -21,7 +21,7 @@ class LandingPageParentDashboardService $semester = (string) ($context['semester'] ?? ''); $parentId = $this->primaryParentResolver->resolveFromCredentials($parentUserId, $userType); - if (! $parentId) { + if (!$parentId) { return [ 'ok' => false, 'message' => 'Unable to retrieve student data. Please contact support.', @@ -38,7 +38,6 @@ class LandingPageParentDashboardService $classSection = StudentClass::getClassSectionsByStudentId($student['id'], $schoolYear); $student['class_section'] = $classSection; $student['grade'] = $classSection; - return $student; }) ->all(); diff --git a/app/Services/Frontend/LandingPageRoleService.php b/app/Services/Frontend/LandingPageRoleService.php index c9785853..54f82436 100644 --- a/app/Services/Frontend/LandingPageRoleService.php +++ b/app/Services/Frontend/LandingPageRoleService.php @@ -9,7 +9,7 @@ class LandingPageRoleService { public function resolveRole(?User $user): string { - if (! $user) { + if (!$user) { return 'guest'; } @@ -22,7 +22,7 @@ class LandingPageRoleService ->map(fn ($r) => strtolower((string) $r)) ->all(); - if (! empty($roles)) { + if (!empty($roles)) { return $roles[0]; } diff --git a/app/Services/Frontend/LandingPageService.php b/app/Services/Frontend/LandingPageService.php index 0a31e4e7..7bdb6376 100644 --- a/app/Services/Frontend/LandingPageService.php +++ b/app/Services/Frontend/LandingPageService.php @@ -11,7 +11,8 @@ class LandingPageService private LandingPageContextService $contextService, private LandingPageTeacherSummaryService $teacherSummaryService, private LandingPageParentDashboardService $parentDashboardService - ) {} + ) { + } public function dashboardForUser(?User $user, ?int $classSectionId = null): array { @@ -45,7 +46,7 @@ class LandingPageService public function teacher(?User $user, ?int $classSectionId = null): array { - if (! $user) { + if (!$user) { return ['role' => 'teacher', 'dashboard' => 'teacher', 'summary' => []]; } @@ -66,7 +67,7 @@ class LandingPageService public function parent(?User $user): array { - if (! $user) { + if (!$user) { return ['role' => 'parent', 'dashboard' => 'parent', 'summary' => []]; } diff --git a/app/Services/Frontend/LandingPageTeacherSummaryService.php b/app/Services/Frontend/LandingPageTeacherSummaryService.php index 38ce2a95..bd2fe95a 100644 --- a/app/Services/Frontend/LandingPageTeacherSummaryService.php +++ b/app/Services/Frontend/LandingPageTeacherSummaryService.php @@ -8,6 +8,7 @@ use App\Models\Calendar; use App\Models\ClassSection; use App\Models\ScoreComment; use App\Models\SemesterScore; +use App\Models\StudentClass; use App\Models\TeacherClass; use DateTimeImmutable; use DateTimeZone; @@ -15,7 +16,9 @@ use Illuminate\Support\Facades\DB; class LandingPageTeacherSummaryService { - public function __construct(private LandingPageContextService $context) {} + public function __construct(private LandingPageContextService $context) + { + } public function summary(int $teacherId, ?int $requestedClassSectionId = null): array { @@ -32,7 +35,7 @@ class LandingPageTeacherSummaryService $activeId = null; if ($requestedClassSectionId && in_array($requestedClassSectionId, $availableIds, true)) { $activeId = $requestedClassSectionId; - } elseif (! empty($availableIds)) { + } elseif (!empty($availableIds)) { $activeId = $availableIds[0]; } @@ -45,7 +48,7 @@ class LandingPageTeacherSummaryService } $normalizedSemester = ucfirst(strtolower(trim((string) $semester))); - if (! in_array($normalizedSemester, ['Fall', 'Spring'], true)) { + if (!in_array($normalizedSemester, ['Fall', 'Spring'], true)) { $normalizedSemester = 'Fall'; } @@ -111,7 +114,7 @@ class LandingPageTeacherSummaryService ]; $uniqueStudentIds = []; - if (! empty($classSectionIds)) { + if (!empty($classSectionIds)) { $studentRows = DB::table('student_class as sc') ->select('sc.student_id', 'sc.class_section_id') ->join('students as s', 's.id', '=', 'sc.student_id') @@ -133,7 +136,7 @@ class LandingPageTeacherSummaryService $summary['attendanceSummary']['students'] = $totalStudents; $scoreRows = []; - if (! empty($classSectionIds)) { + if (!empty($classSectionIds)) { $scoreRows = SemesterScore::query() ->select(['student_id', 'class_section_id', 'midterm_exam_score', 'final_exam_score', 'participation_score']) ->whereIn('class_section_id', $classSectionIds) @@ -211,7 +214,7 @@ class LandingPageTeacherSummaryService ]; $commentRows = []; - if (! empty($uniqueStudentIds)) { + if (!empty($uniqueStudentIds)) { $commentRows = ScoreComment::query() ->select(['student_id', 'score_type', 'comment', 'comment_review']) ->whereIn('student_id', $uniqueStudentIds) @@ -235,7 +238,7 @@ class LandingPageTeacherSummaryService if ($type === '') { $type = 'general'; } - if (! isset($commentStats[$type])) { + if (!isset($commentStats[$type])) { $commentStats[$type] = ['pending' => 0, 'reviewed' => 0]; } @@ -258,7 +261,7 @@ class LandingPageTeacherSummaryService } foreach ($expectedCommentTypes as $type) { - if (! isset($commentStats[$type])) { + if (!isset($commentStats[$type])) { $commentStats[$type] = ['pending' => 0, 'reviewed' => 0]; } } @@ -282,7 +285,7 @@ class LandingPageTeacherSummaryService $completionPct = $totalStudents > 0 ? (int) round(min(100, ($filled / $totalStudents) * 100)) : 0; $commentTypes[$type] = [ - 'label' => ucfirst($type).' comments', + 'label' => ucfirst($type) . ' comments', 'pending' => $stats['pending'], 'reviewed' => $stats['reviewed'], 'filled' => $filled, @@ -309,7 +312,7 @@ class LandingPageTeacherSummaryService ]; $attendanceRows = []; - if (! empty($classSectionIds)) { + if (!empty($classSectionIds)) { $attendanceRows = AttendanceRecord::query() ->select(['student_id', 'class_section_id', 'total_absence']) ->whereIn('class_section_id', $classSectionIds) @@ -359,7 +362,7 @@ class LandingPageTeacherSummaryService ->get() ->toArray(); - if ($attendanceStatus['submitted'] === false && ! empty($classSectionIds)) { + if ($attendanceStatus['submitted'] === false && !empty($classSectionIds)) { $summary['attendanceSummary']['completionPct'] = 0; $summary['attendanceSummary']['recorded'] = 0; } @@ -374,22 +377,20 @@ class LandingPageTeacherSummaryService $notifications = []; $buildScoreLink = static function (?string $focus): string { $base = '/teacher/scores'; - - return $focus ? $base.'?focus='.urlencode($focus) : $base; + return $focus ? $base . '?focus=' . urlencode($focus) : $base; }; $determineFocus = static function (array $event): string { $eventTypeText = strtolower(trim((string) ($event['event_type'] ?? ''))); if ($eventTypeText !== '' && str_contains($eventTypeText, 'draft')) { return 'comments'; } - $text = strtolower(trim(($event['title'] ?? '').' '.($event['description'] ?? ''))); + $text = strtolower(trim(($event['title'] ?? '') . ' ' . ($event['description'] ?? ''))); if ($text === '') { return 'scores'; } if (str_contains($text, 'comment') || str_contains($text, 'ptap')) { return 'comments'; } - return 'scores'; }; $calendarLink = '/teacher/calendar'; @@ -442,13 +443,12 @@ class LandingPageTeacherSummaryService $notifications[] = [ 'type' => 'danger', 'message' => sprintf( - 'Deadline today: %s is due. Submit the remaining entries before the day ends.', + "Deadline today: %s is due. Submit the remaining entries before the day ends.", $matchedType ), 'link' => $buildScoreLink($eventFocus), 'linkText' => 'Submit now', ]; - continue; } @@ -460,7 +460,7 @@ class LandingPageTeacherSummaryService $notifications[] = [ 'type' => 'warning', 'message' => sprintf( - '%s is due on %s%s. Review it on the calendar so you don’t miss it.', + "%s is due on %s%s. Review it on the calendar so you don’t miss it.", $matchedType, $eventDateTime->format('M j, Y'), $relativeText @@ -470,13 +470,13 @@ class LandingPageTeacherSummaryService ]; } - if (! $activeDeadline) { + if (!$activeDeadline) { $scoreLabel = $summary['scoreSummary']['fieldLabel'] ?? 'Score'; - if (! empty($summary['scoreSummary']['missing'] ?? 0)) { + if (!empty($summary['scoreSummary']['missing'] ?? 0)) { $notifications[] = [ 'type' => 'warning', 'message' => sprintf( - 'You have %s %s entries missing on the scores page. Please finish submitting them.', + "You have %s %s entries missing on the scores page. Please finish submitting them.", (int) $summary['scoreSummary']['missing'], $scoreLabel ), @@ -493,20 +493,20 @@ class LandingPageTeacherSummaryService $notifications[] = [ 'type' => 'warning', 'message' => sprintf( - '%s comment missing for %s student(s). Leave comments on the scores page.', + "%s comment missing for %s student(s). Leave comments on the scores page.", ucfirst($type), $count ), 'link' => $buildScoreLink('comments'), - 'linkText' => ucfirst($type).' comments', + 'linkText' => ucfirst($type) . ' comments', ]; } - if (! empty($summary['participationSummary']['missing'] ?? 0)) { + if (!empty($summary['participationSummary']['missing'] ?? 0)) { $notifications[] = [ 'type' => 'warning', 'message' => sprintf( - 'Participation entries are still missing for %s student(s). Please add them from the scores page.', + "Participation entries are still missing for %s student(s). Please add them from the scores page.", (int) $summary['participationSummary']['missing'] ), 'link' => $buildScoreLink('scores'), @@ -515,11 +515,11 @@ class LandingPageTeacherSummaryService } } - if (! empty($summary['attendanceStatus']['missingSections'] ?? [])) { + if (!empty($summary['attendanceStatus']['missingSections'] ?? [])) { $missingNames = $summary['attendanceStatus']['missingNames'] ?? []; $label = ''; - if (! empty($missingNames)) { - $label = ' ('.implode(', ', array_slice($missingNames, 0, 3)).(count($missingNames) > 3 ? '…' : '').')'; + if (!empty($missingNames)) { + $label = ' (' . implode(', ', array_slice($missingNames, 0, 3)) . (count($missingNames) > 3 ? '…' : '') . ')'; } $notifications[] = [ 'type' => 'danger', @@ -564,13 +564,13 @@ class LandingPageTeacherSummaryService $missingSections = []; foreach ($classSectionIds as $classSectionId) { $status = $statusMap[$classSectionId] ?? ''; - if (! in_array($status, ['submitted', 'published', 'finalized'], true)) { + if (!in_array($status, ['submitted', 'published', 'finalized'], true)) { $missingSections[] = $classSectionId; } } $missingNames = []; - if (! empty($missingSections)) { + if (!empty($missingSections)) { $sectionRows = ClassSection::query() ->select(['class_section_id', 'class_section_name']) ->whereIn('class_section_id', $missingSections) diff --git a/app/Services/Frontend/ProfileIconService.php b/app/Services/Frontend/ProfileIconService.php index b58c44ef..97be1848 100644 --- a/app/Services/Frontend/ProfileIconService.php +++ b/app/Services/Frontend/ProfileIconService.php @@ -9,7 +9,7 @@ class ProfileIconService public function buildForUser(int $userId): array { $user = User::query()->find($userId); - if (! $user) { + if (!$user) { return [ 'userName' => 'User not found', 'userInitials' => '??', @@ -28,7 +28,7 @@ class ProfileIconService } return [ - 'userName' => trim($firstname.' '.$lastname), + 'userName' => trim($firstname . ' ' . $lastname), 'userInitials' => $initials !== '' ? $initials : '??', ]; } diff --git a/app/Services/Frontend/StaticPageService.php b/app/Services/Frontend/StaticPageService.php index 3edc2387..eea1eca6 100644 --- a/app/Services/Frontend/StaticPageService.php +++ b/app/Services/Frontend/StaticPageService.php @@ -7,9 +7,9 @@ class StaticPageService public function load(string $filename, string $type): array { $safeName = basename($filename); - $path = public_path('html/'.$safeName); + $path = public_path('html/' . $safeName); - if (! is_file($path) || ! is_readable($path)) { + if (!is_file($path) || !is_readable($path)) { return [ 'ok' => false, 'error' => 'Page content not available.', diff --git a/app/Services/Grading/BelowSixtyEmailService.php b/app/Services/Grading/BelowSixtyEmailService.php index 37357e66..906c2a55 100644 --- a/app/Services/Grading/BelowSixtyEmailService.php +++ b/app/Services/Grading/BelowSixtyEmailService.php @@ -2,14 +2,16 @@ namespace App\Services\Grading; -use App\Services\EmailService; use App\Support\MailHtml; +use App\Services\EmailService; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; class BelowSixtyEmailService { - public function __construct(private EmailService $emailService) {} + public function __construct(private EmailService $emailService) + { + } public function send(array $payload): array { @@ -23,7 +25,6 @@ class BelowSixtyEmailService if ($studentId <= 0) { Log::warning('Below60Email: missing student_id'); - return ['ok' => false, 'message' => 'Missing student id.']; } @@ -41,7 +42,6 @@ class BelowSixtyEmailService if (empty($rows)) { Log::warning('Below60Email: no guardian emails', ['student_id' => $studentId]); - return ['ok' => false, 'message' => 'No guardian email addresses.']; } @@ -57,17 +57,17 @@ class BelowSixtyEmailService $primary = $rows[0] ?? null; $parentName = ''; if ($primary) { - $parentName = trim((string) ($primary->firstname ?? '').' '.(string) ($primary->lastname ?? '')); + $parentName = trim((string) ($primary->firstname ?? '') . ' ' . (string) ($primary->lastname ?? '')); } $subject = (string) ($payload['subject'] ?? ''); if ($subject === '') { $subject = 'Student Performance Alert'; if ($studentName !== '') { - $subject .= ' — '.$studentName; + $subject .= ' — ' . $studentName; } if ($semester !== '' || $schoolYear !== '') { - $subject .= ' ('.trim($semester.' '.$schoolYear).')'; + $subject .= ' (' . trim($semester . ' ' . $schoolYear) . ')'; } } diff --git a/app/Services/Grading/GradingBelowSixtyService.php b/app/Services/Grading/GradingBelowSixtyService.php index c804e95b..6ceb5fa5 100644 --- a/app/Services/Grading/GradingBelowSixtyService.php +++ b/app/Services/Grading/GradingBelowSixtyService.php @@ -6,6 +6,7 @@ use App\Models\BelowSixtyDecision; use App\Models\CurrentFlag; use App\Models\ParentMeetingSchedule; use App\Models\ScoreComment; +use App\Models\Student; use App\Models\StudentDecision; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Event; @@ -57,7 +58,7 @@ class GradingBelowSixtyService $studentIds = array_values(array_filter($studentIds, static fn ($id) => $id > 0)); $commentMap = []; - if (! empty($studentIds)) { + if (!empty($studentIds)) { $commentRows = ScoreComment::query() ->select('student_id', 'comment', 'created_at') ->where('score_type', 'general') @@ -68,14 +69,14 @@ class GradingBelowSixtyService ->get(); foreach ($commentRows as $row) { $sid = (int) $row->student_id; - if ($sid > 0 && ! isset($commentMap[$sid])) { + if ($sid > 0 && !isset($commentMap[$sid])) { $commentMap[$sid] = (string) ($row->comment ?? ''); } } } $statusMap = []; - if (! empty($studentIds)) { + if (!empty($studentIds)) { $flagRows = CurrentFlag::query() ->select('student_id', 'flag_state') ->where('flag', 'grade') @@ -109,7 +110,7 @@ class GradingBelowSixtyService throw new RuntimeException('Student record not found for the selected term.'); } - $studentName = trim((string) ($row['firstname'] ?? '').' '.(string) ($row['lastname'] ?? '')); + $studentName = trim((string) ($row['firstname'] ?? '') . ' ' . (string) ($row['lastname'] ?? '')); $subject = $this->buildBelowSixtySubject($studentName, $semester, $schoolYear); $parentName = $this->fetchBelowSixtyParentName($studentId); @@ -145,7 +146,7 @@ class GradingBelowSixtyService public function updateStatus(int $studentId, string $semester, string $schoolYear, string $status, string $note, ?int $userId): void { $status = ucfirst(strtolower($status)); - if (! in_array($status, ['Open', 'Closed'], true)) { + if (!in_array($status, ['Open', 'Closed'], true)) { throw new RuntimeException('Invalid status.'); } @@ -169,22 +170,21 @@ class GradingBelowSixtyService $data['updated_by_open'] = $userId; if ($note !== '') { $prev = (string) ($existing->open_description ?? ''); - $data['open_description'] = trim($prev.PHP_EOL.$note); + $data['open_description'] = trim($prev . PHP_EOL . $note); } } else { $data['updated_by_closed'] = $userId; if ($note !== '') { $prev = (string) ($existing->close_description ?? ''); - $data['close_description'] = trim($prev.PHP_EOL.$note); + $data['close_description'] = trim($prev . PHP_EOL . $note); } } $existing->update($data); - return; } $row = $this->fetchBelowSixtyEmailRow($studentId, $schoolYear, $semester); - $studentName = trim((string) ($row['firstname'] ?? '').' '.(string) ($row['lastname'] ?? '')); + $studentName = trim((string) ($row['firstname'] ?? '') . ' ' . (string) ($row['lastname'] ?? '')); $grade = (string) ($row['class_section_name'] ?? ''); $data = [ 'student_id' => $studentId, @@ -298,7 +298,7 @@ class GradingBelowSixtyService continue; } - if (! isset($studentMap[$studentId])) { + if (!isset($studentMap[$studentId])) { $studentMap[$studentId] = [ 'student_id' => $studentId, 'school_id' => $row->school_id, @@ -355,7 +355,7 @@ class GradingBelowSixtyService $certificateMap = []; foreach ($certificateRows as $row) { $studentId = (int) ($row->student_id ?? 0); - if ($studentId > 0 && ! isset($certificateMap[$studentId])) { + if ($studentId > 0 && !isset($certificateMap[$studentId])) { $certificateMap[$studentId] = (string) ($row->certificate_number ?? ''); } } @@ -522,8 +522,8 @@ class GradingBelowSixtyService } $subject = 'Whole Year Academic Decision — ' - .(string) ($context['student_name'] ?? 'Student') - .' ('.$schoolYear.')'; + . (string) ($context['student_name'] ?? 'Student') + . ' (' . $schoolYear . ')'; return [ 'student_id' => $studentId, @@ -553,8 +553,8 @@ class GradingBelowSixtyService $resolvedSubject = trim((string) $subject); if ($resolvedSubject === '') { $resolvedSubject = 'Whole Year Academic Decision — ' - .(string) ($context['student_name'] ?? 'Student') - .' ('.$schoolYear.')'; + . (string) ($context['student_name'] ?? 'Student') + . ' (' . $schoolYear . ')'; } $payload = [ @@ -628,7 +628,7 @@ class GradingBelowSixtyService continue; } - if (! isset($studentMap[$studentId])) { + if (!isset($studentMap[$studentId])) { $studentMap[$studentId] = [ 'school_id' => $row->school_id, 'firstname' => $row->firstname, @@ -661,7 +661,7 @@ class GradingBelowSixtyService if ($studentId <= 0) { continue; } - if (! isset($belowMap[$studentId]) || trim((string) ($belowMap[$studentId]->decision ?? '')) === '') { + if (!isset($belowMap[$studentId]) || trim((string) ($belowMap[$studentId]->decision ?? '')) === '') { $belowMap[$studentId] = $row; } } @@ -754,7 +754,7 @@ class GradingBelowSixtyService return [ 'rows' => $rows, - 'generated' => ! empty($savedMap), + 'generated' => !empty($savedMap), 'school_year' => $schoolYear, ]; } @@ -789,7 +789,7 @@ class GradingBelowSixtyService continue; } - if (! isset($studentMap[$studentId])) { + if (!isset($studentMap[$studentId])) { $studentMap[$studentId] = [ 'firstname' => $row->firstname, 'lastname' => $row->lastname, @@ -818,7 +818,7 @@ class GradingBelowSixtyService if ($studentId <= 0) { continue; } - if (! isset($belowMap[$studentId]) || trim((string) ($belowMap[$studentId]->decision ?? '')) === '') { + if (!isset($belowMap[$studentId]) || trim((string) ($belowMap[$studentId]->decision ?? '')) === '') { $belowMap[$studentId] = $row; } } @@ -912,7 +912,7 @@ class GradingBelowSixtyService ->whereRaw('LOWER(TRIM(ss.semester)) = ?', [$semesterKey]) ->first(); - if (! $row) { + if (!$row) { return []; } @@ -972,7 +972,7 @@ class GradingBelowSixtyService ]; } - if (! empty($semesters)) { + if (!empty($semesters)) { $commentRows = DB::table('score_comments') ->select('semester', 'score_type', 'comment', 'created_at') ->where('student_id', $studentId) @@ -987,7 +987,7 @@ class GradingBelowSixtyService foreach ($commentRows as $row) { $semester = ucfirst(strtolower(trim((string) ($row->semester ?? '')))); $type = strtolower(trim((string) ($row->score_type ?? 'general'))); - if (isset($semesters[$semester]) && ! isset($semesters[$semester]['comments'][$type])) { + if (isset($semesters[$semester]) && !isset($semesters[$semester]['comments'][$type])) { $semesters[$semester]['comments'][$type] = (string) ($row->comment ?? ''); } } @@ -1001,24 +1001,23 @@ class GradingBelowSixtyService $parentName = 'Parent/Guardian'; try { $rows = DB::select( - 'SELECT u.firstname, u.lastname + "SELECT u.firstname, u.lastname FROM family_students fs JOIN family_guardians fg ON fg.family_id = fs.family_id JOIN users u ON u.id = fg.user_id WHERE fs.student_id = ? ORDER BY fg.is_primary DESC, u.lastname, u.firstname - LIMIT 1', + LIMIT 1", [$studentId] ); - if (! empty($rows[0])) { - $candidate = trim((string) ($rows[0]->firstname ?? '').' '.(string) ($rows[0]->lastname ?? '')); + if (!empty($rows[0])) { + $candidate = trim((string) ($rows[0]->firstname ?? '') . ' ' . (string) ($rows[0]->lastname ?? '')); if ($candidate !== '') { $parentName = $candidate; } } } catch (\Throwable $e) { } - return $parentName; } @@ -1042,7 +1041,7 @@ class GradingBelowSixtyService ]; } - $studentName = trim((string) ($student->firstname ?? '').' '.(string) ($student->lastname ?? '')); + $studentName = trim((string) ($student->firstname ?? '') . ' ' . (string) ($student->lastname ?? '')); if ($studentName === '') { $studentName = 'Student'; } @@ -1141,22 +1140,22 @@ class GradingBelowSixtyService $html = '

Dear Parent/Guardian,

- This message is regarding '.e($studentName).' - for the '.e($schoolYear).' school year. + This message is regarding ' . e($studentName) . ' + for the ' . e($schoolYear) . ' school year.

- Class: '.e($classSectionName !== '' ? $classSectionName : 'N/A').'
- Fall Score: '.e($fallText).'
- Spring Score: '.e($springText).'
- Whole-Year Score: '.e($yearText).'
- Decision: '.e($decision).' + Class: ' . e($classSectionName !== '' ? $classSectionName : 'N/A') . '
+ Fall Score: ' . e($fallText) . '
+ Spring Score: ' . e($springText) . '
+ Whole-Year Score: ' . e($yearText) . '
+ Decision: ' . e($decision) . '

'; if ($notes !== '') { $html .= '

Decision Notes:
- '.nl2br(e($notes)).' + ' . nl2br(e($notes)) . '

'; } @@ -1313,9 +1312,9 @@ class GradingBelowSixtyService $classSectionName = trim((string) ($semester['class_section_name'] ?? '')); $html .= '

- '.e($semesterName).' Semester'; + ' . e($semesterName) . ' Semester'; if ($classSectionName !== '') { - $html .= ' — '.e($classSectionName); + $html .= ' — ' . e($classSectionName); } $html .= '

@@ -1330,7 +1329,7 @@ class GradingBelowSixtyService $hasScoreRow = false; foreach ($scoreLabels as $key => $label) { - if (! array_key_exists($key, $semester)) { + if (!array_key_exists($key, $semester)) { continue; } $value = $semester[$key]; @@ -1341,13 +1340,13 @@ class GradingBelowSixtyService $fontWeight = $key === 'semester_score' ? 'font-weight:bold;' : ''; $html .= ' - '.e($label).' - '.e($scoreText).' + ' . e($label) . ' + ' . e($scoreText) . ' '; $hasScoreRow = true; } - if (! $hasScoreRow) { + if (!$hasScoreRow) { $html .= ' No scores recorded. @@ -1359,7 +1358,7 @@ class GradingBelowSixtyService '; $comments = is_array($semester['comments'] ?? null) ? $semester['comments'] : []; - if (! empty($comments)) { + if (!empty($comments)) { $deduped = []; $seen = []; foreach ($comments as $type => $text) { @@ -1368,7 +1367,7 @@ class GradingBelowSixtyService continue; } $label = $commentTypeLabels[$type] ?? (string) $type; - $hash = $label.'|'.$text; + $hash = $label . '|' . $text; if (isset($seen[$hash])) { continue; } @@ -1376,13 +1375,13 @@ class GradingBelowSixtyService $deduped[] = ['label' => $label, 'text' => $text]; } - if (! empty($deduped)) { + if (!empty($deduped)) { $html .= '

Comments

'; foreach ($deduped as $comment) { $html .= '

- '.e($comment['label']).':
- '.nl2br(e($comment['text'])).' + ' . e($comment['label']) . ':
+ ' . nl2br(e($comment['text'])) . '

'; } } @@ -1396,12 +1395,11 @@ class GradingBelowSixtyService { $subject = 'Student Performance Alert'; if ($studentName !== '') { - $subject .= ' — '.$studentName; + $subject .= ' — ' . $studentName; } if ($semester !== '' || $schoolYear !== '') { - $subject .= ' ('.trim($semester.' '.$schoolYear).')'; + $subject .= ' (' . trim($semester . ' ' . $schoolYear) . ')'; } - return $subject; } @@ -1416,18 +1414,18 @@ class GradingBelowSixtyService $parentUserId = null; try { $pRows = DB::select( - 'SELECT u.id AS user_id, u.firstname, u.lastname + "SELECT u.id AS user_id, u.firstname, u.lastname FROM family_students fs JOIN family_guardians fg ON fg.family_id = fs.family_id JOIN users u ON u.id = fg.user_id WHERE fs.student_id = ? ORDER BY fg.is_primary DESC, u.lastname, u.firstname - LIMIT 1', + LIMIT 1", [$studentId] ); - if (! empty($pRows[0])) { + if (!empty($pRows[0])) { $parentUserId = (int) ($pRows[0]->user_id ?? 0) ?: null; - $parentName = trim((string) ($pRows[0]->firstname ?? '').' '.(string) ($pRows[0]->lastname ?? '')); + $parentName = trim((string) ($pRows[0]->firstname ?? '') . ' ' . (string) ($pRows[0]->lastname ?? '')); if ($parentName === '') { $parentName = 'Parent/Guardian'; } @@ -1438,16 +1436,16 @@ class GradingBelowSixtyService if ($parentUserId === null) { try { $srow = DB::selectOne( - 'SELECT s.parent_id, u.firstname, u.lastname + "SELECT s.parent_id, u.firstname, u.lastname FROM students s LEFT JOIN users u ON u.id = s.parent_id WHERE s.id = ? - LIMIT 1', + LIMIT 1", [$studentId] ); - if (! empty($srow)) { + if (!empty($srow)) { $parentUserId = (int) ($srow->parent_id ?? 0) ?: null; - $fallbackName = trim((string) ($srow->firstname ?? '').' '.(string) ($srow->lastname ?? '')); + $fallbackName = trim((string) ($srow->firstname ?? '') . ' ' . (string) ($srow->lastname ?? '')); if ($fallbackName !== '') { $parentName = $fallbackName; } @@ -1456,7 +1454,7 @@ class GradingBelowSixtyService } } - $studentName = trim((string) ($row['firstname'] ?? '').' '.(string) ($row['lastname'] ?? '')); + $studentName = trim((string) ($row['firstname'] ?? '') . ' ' . (string) ($row['lastname'] ?? '')); return [ 'student_name' => $studentName !== '' ? $studentName : 'Student', diff --git a/app/Services/Grading/GradingLockService.php b/app/Services/Grading/GradingLockService.php index e343df9b..c5ba695e 100644 --- a/app/Services/Grading/GradingLockService.php +++ b/app/Services/Grading/GradingLockService.php @@ -2,11 +2,11 @@ namespace App\Services\Grading; -use App\Models\ClassSection; use App\Models\GradingLock; +use App\Models\ClassSection; +use RuntimeException; use App\Services\Grading\Policy\GradingPolicyResolver; use App\Services\Grading\Validation\GradebookFinalizationValidator; -use RuntimeException; class GradingLockService { @@ -14,8 +14,8 @@ class GradingLockService private ?GradingPolicyResolver $policyResolver = null, private ?GradebookFinalizationValidator $finalizationValidator = null ) { - $this->policyResolver = $this->policyResolver ?? new GradingPolicyResolver; - $this->finalizationValidator = $this->finalizationValidator ?? new GradebookFinalizationValidator; + $this->policyResolver = $this->policyResolver ?? new GradingPolicyResolver(); + $this->finalizationValidator = $this->finalizationValidator ?? new GradebookFinalizationValidator(); } public function toggle(int $classSectionId, string $semester, string $schoolYear, ?int $userId): bool @@ -32,7 +32,6 @@ class GradingLockService 'locked_by' => null, 'locked_at' => null, ]); - return false; } @@ -98,7 +97,7 @@ class GradingLockService foreach ($sectionIds as $sid) { $this->assertCanLock($sid, $semester, $schoolYear); - if (! empty($existingBySection[$sid])) { + if (!empty($existingBySection[$sid])) { if ($existingBySection[$sid]->is_locked) { continue; } @@ -108,7 +107,6 @@ class GradingLockService 'locked_at' => $now, ]); $count++; - continue; } @@ -125,7 +123,7 @@ class GradingLockService $count++; } - if (! empty($insertRows)) { + if (!empty($insertRows)) { GradingLock::query()->insert($insertRows); } @@ -140,7 +138,7 @@ class GradingLockService } $result = $this->finalizationValidator->validateClassSectionBeforeLock($classSectionId, $semester, $schoolYear); - if (! $result['valid']) { + if (!$result['valid']) { $count = count($result['errors']); throw new RuntimeException("Cannot lock class section {$classSectionId}; strong grading validation failed with {$count} error(s)."); } diff --git a/app/Services/Grading/GradingOverviewService.php b/app/Services/Grading/GradingOverviewService.php index 72b67bd6..3bfb14d9 100644 --- a/app/Services/Grading/GradingOverviewService.php +++ b/app/Services/Grading/GradingOverviewService.php @@ -8,7 +8,9 @@ use Illuminate\Support\Facades\DB; class GradingOverviewService { - public function __construct() {} + public function __construct() + { + } public function overview(?int $classId, ?string $semester, ?string $schoolYear): array { @@ -36,7 +38,7 @@ class GradingOverviewService continue; } - if (! isset($grades[$classIdValue])) { + if (!isset($grades[$classIdValue])) { $grades[$classIdValue] = []; } $exists = false; @@ -46,7 +48,7 @@ class GradingOverviewService break; } } - if (! $exists) { + if (!$exists) { $grades[$classIdValue][] = [ 'class_section_id' => $sectionId, 'class_section_name' => $sectionName, @@ -246,7 +248,6 @@ class GradingOverviewService if ($value === null || $value === '') { return null; } - return round((float) $value, 2); } @@ -259,7 +260,6 @@ class GradingOverviewService return null; } } - return $score; } @@ -271,7 +271,6 @@ class GradingOverviewService return $option; } } - return $requestedSemester; } if ($fallbackSemester !== null && $fallbackSemester !== '') { @@ -280,10 +279,8 @@ class GradingOverviewService return $option; } } - return $fallbackSemester; } - return $semesterOptions[0] ?? ''; } @@ -309,7 +306,7 @@ class GradingOverviewService $semesters = ['Fall', 'Spring']; } - if ($fallbackSemester !== null && $fallbackSemester !== '' && ! in_array($fallbackSemester, $semesters, true)) { + if ($fallbackSemester !== null && $fallbackSemester !== '' && !in_array($fallbackSemester, $semesters, true)) { array_unshift($semesters, $fallbackSemester); } @@ -325,7 +322,6 @@ class GradingOverviewService if ($norm === 'spring') { return 'parent_scores_released_spring'; } - return null; } @@ -334,14 +330,13 @@ class GradingOverviewService $key = $this->getParentReleaseKey($semester); $raw = $key ? Configuration::getConfig($key) : null; $raw = (string) ($raw ?? ''); - return in_array(strtolower(trim($raw)), ['1', 'true', 'yes', 'y', 'on'], true); } private function ensureParentReleaseKeyExists(string $semester): void { $key = $this->getParentReleaseKey($semester); - if (! $key) { + if (!$key) { return; } diff --git a/app/Services/Grading/GradingPlacementService.php b/app/Services/Grading/GradingPlacementService.php index b0edfcf6..63a36d2f 100644 --- a/app/Services/Grading/GradingPlacementService.php +++ b/app/Services/Grading/GradingPlacementService.php @@ -14,7 +14,7 @@ class GradingPlacementService { public function placementContext(?int $classSectionId, string $schoolYear, ?string $placementTest, ?string $open): array { - if (! $classSectionId) { + if (!$classSectionId) { $showStudents = ($placementTest !== '' && $open === '1'); $students = $showStudents ? $this->fetchActiveStudentsWithSection($schoolYear) : []; $batches = $this->fetchPlacementBatches($schoolYear); @@ -40,7 +40,7 @@ class GradingPlacementService ), static fn ($id) => $id > 0)); $levels = []; - if (! empty($studentIds)) { + if (!empty($studentIds)) { $rows = PlacementLevel::query() ->whereIn('student_id', $studentIds) ->where('school_year', $schoolYear) @@ -67,7 +67,7 @@ class GradingPlacementService } $level = $level === '' || $level === null ? null : (int) $level; - if ($level !== null && ! in_array($level, [1, 2, 3], true)) { + if ($level !== null && !in_array($level, [1, 2, 3], true)) { throw new RuntimeException('Invalid placement level.'); } @@ -80,7 +80,6 @@ class GradingPlacementService if ($existing) { $existing->delete(); } - return; } @@ -113,7 +112,7 @@ class GradingPlacementService $validSet = array_flip($validIds); $existingRows = []; - if (! empty($validIds)) { + if (!empty($validIds)) { $rows = PlacementLevel::query() ->whereIn('student_id', $validIds) ->where('school_year', $schoolYear) @@ -125,12 +124,12 @@ class GradingPlacementService foreach ($levels as $studentIdRaw => $levelRaw) { $studentId = (int) $studentIdRaw; - if (! isset($validSet[$studentId])) { + if (!isset($validSet[$studentId])) { continue; } $levelRaw = trim((string) $levelRaw); $level = $levelRaw === '' ? null : (int) $levelRaw; - if ($level !== null && ! in_array($level, [1, 2, 3], true)) { + if ($level !== null && !in_array($level, [1, 2, 3], true)) { continue; } @@ -138,7 +137,6 @@ class GradingPlacementService if (isset($existingRows[$studentId])) { $existingRows[$studentId]->delete(); } - continue; } @@ -181,7 +179,7 @@ class GradingPlacementService $savedCount = 0; foreach ($levels as $studentIdRaw => $levelRaw) { $studentId = (int) $studentIdRaw; - if (! isset($validSet[$studentId])) { + if (!isset($validSet[$studentId])) { continue; } $levelRaw = trim((string) $levelRaw); @@ -214,7 +212,7 @@ class GradingPlacementService public function getPlacementBatch(int $batchId): array { $batch = PlacementBatch::query()->find($batchId); - if (! $batch) { + if (!$batch) { throw new RuntimeException('Placement batch not found.'); } @@ -232,7 +230,7 @@ class GradingPlacementService public function updatePlacementBatch(int $batchId, string $schoolYear, array $levels, ?int $userId): void { $batch = PlacementBatch::query()->find($batchId); - if (! $batch) { + if (!$batch) { throw new RuntimeException('Placement batch not found.'); } @@ -247,7 +245,7 @@ class GradingPlacementService foreach ($levels as $studentIdRaw => $scoreRaw) { $studentId = (int) $studentIdRaw; - if (! isset($validSet[$studentId])) { + if (!isset($validSet[$studentId])) { continue; } $scoreRaw = trim((string) $scoreRaw); @@ -255,7 +253,6 @@ class GradingPlacementService if (isset($existing[$studentId])) { PlacementScore::query()->whereKey($existing[$studentId]['id'])->delete(); } - continue; } $score = (int) $scoreRaw; diff --git a/app/Services/Grading/GradingRefreshService.php b/app/Services/Grading/GradingRefreshService.php index d8b19ce3..d43c3589 100644 --- a/app/Services/Grading/GradingRefreshService.php +++ b/app/Services/Grading/GradingRefreshService.php @@ -10,7 +10,9 @@ use RuntimeException; class GradingRefreshService { - public function __construct(private SemesterScoreService $semesterScoreService) {} + public function __construct(private SemesterScoreService $semesterScoreService) + { + } public function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void { @@ -33,7 +35,7 @@ class GradingRefreshService private function refreshAttendanceComments(int $classSectionId, string $semester, string $schoolYear): void { - if (! function_exists('attendance_comment_from_score')) { + if (!function_exists('attendance_comment_from_score')) { return; } diff --git a/app/Services/Grading/GradingScoreService.php b/app/Services/Grading/GradingScoreService.php index 2b52548f..7896c093 100644 --- a/app/Services/Grading/GradingScoreService.php +++ b/app/Services/Grading/GradingScoreService.php @@ -2,7 +2,6 @@ namespace App\Services\Grading; -use App\Models\ClassSection; use App\Models\FinalExam; use App\Models\GradingLock; use App\Models\Homework; @@ -12,20 +11,23 @@ use App\Models\Quiz; use App\Models\ScoreComment; use App\Models\SemesterScore; use App\Models\Student; +use App\Models\ClassSection; use App\Services\Grading\Validation\ScoreValueValidator; use App\Services\Scores\SemesterScoreService; use RuntimeException; class GradingScoreService { - public function __construct(private SemesterScoreService $semesterScoreService) {} + public function __construct(private SemesterScoreService $semesterScoreService) + { + } public function show(string $type, int $classSectionId, int $studentId, string $semester, string $schoolYear): array { $model = $this->resolveModel($type); $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { throw new RuntimeException('Student not found.'); } @@ -71,9 +73,9 @@ class GradingScoreService $scores = $payload['scores'] ?? []; $comments = $payload['comments'] ?? []; - $validator = new ScoreValueValidator; + $validator = new ScoreValueValidator(); foreach ($scoreIds as $i => $id) { - $normalizedScore = $validator->normalizeNullable($scores[$i] ?? null, ScoreValueValidator::DEFAULT_MAX_POINTS, ucfirst($type).' score'); + $normalizedScore = $validator->normalizeNullable($scores[$i] ?? null, ScoreValueValidator::DEFAULT_MAX_POINTS, ucfirst($type) . ' score'); $model->newQuery()->whereKey($id)->update([ 'score' => $normalizedScore, 'max_points' => ScoreValueValidator::DEFAULT_MAX_POINTS, @@ -84,8 +86,8 @@ class GradingScoreService } } elseif (in_array($type, ['midterm', 'final', 'test'], true)) { $score = $payload['score'] ?? null; - $validator = new ScoreValueValidator; - $normalizedScore = $validator->normalizeNullable($score, ScoreValueValidator::DEFAULT_MAX_POINTS, ucfirst($type).' score'); + $validator = new ScoreValueValidator(); + $normalizedScore = $validator->normalizeNullable($score, ScoreValueValidator::DEFAULT_MAX_POINTS, ucfirst($type) . ' score'); $data = [ 'score' => $normalizedScore, @@ -133,7 +135,7 @@ class GradingScoreService } $studentTeacherInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, $updatedBy); - if (! empty($studentTeacherInfo)) { + if (!empty($studentTeacherInfo)) { try { $this->semesterScoreService->updateScoresForStudents($studentTeacherInfo, $semester, $schoolYear); } catch (RuntimeException $e) { @@ -187,13 +189,13 @@ class GradingScoreService private function resolveModel(string $type) { return match ($type) { - 'homework' => new Homework, - 'quiz' => new Quiz, - 'project' => new Project, - 'midterm' => new MidtermExam, - 'final' => new FinalExam, - 'test' => new SemesterScore, - 'comments' => new ScoreComment, + 'homework' => new Homework(), + 'quiz' => new Quiz(), + 'project' => new Project(), + 'midterm' => new MidtermExam(), + 'final' => new FinalExam(), + 'test' => new SemesterScore(), + 'comments' => new ScoreComment(), default => throw new RuntimeException("Invalid type: {$type}"), }; } diff --git a/app/Services/Grading/HomeworkTrackingCalendarService.php b/app/Services/Grading/HomeworkTrackingCalendarService.php index 4a5f2f7a..bc3568e1 100644 --- a/app/Services/Grading/HomeworkTrackingCalendarService.php +++ b/app/Services/Grading/HomeworkTrackingCalendarService.php @@ -15,7 +15,6 @@ class HomeworkTrackingCalendarService } if ($startYear === null) { $today = new DateTime('today'); - return [$today, $today]; } @@ -32,7 +31,6 @@ class HomeworkTrackingCalendarService } } catch (\Throwable $e) { $today = new DateTime('today'); - return [$today, $today]; } @@ -75,7 +73,7 @@ class HomeworkTrackingCalendarService $dateToIndex = []; $idx = 0; foreach ($sundays as $ymd) { - if (! isset($eventDays[$ymd])) { + if (!isset($eventDays[$ymd])) { $idx++; $dateToIndex[$ymd] = $idx; } else { diff --git a/app/Services/Grading/HomeworkTrackingService.php b/app/Services/Grading/HomeworkTrackingService.php index 94516870..d92690ca 100644 --- a/app/Services/Grading/HomeworkTrackingService.php +++ b/app/Services/Grading/HomeworkTrackingService.php @@ -9,7 +9,9 @@ class HomeworkTrackingService { private array $teacherAssignmentCache = []; - public function __construct(private HomeworkTrackingCalendarService $calendarService) {} + public function __construct(private HomeworkTrackingCalendarService $calendarService) + { + } public function report(?string $semester = null, ?string $schoolYear = null, int $page = 1): array { @@ -120,7 +122,7 @@ class HomeworkTrackingService $date = substr((string) ($row->hw_date ?? ''), 0, 10); $cnt = (int) $row->cnt; $firstCreated = substr((string) ($row->first_created ?? ''), 0, 10); - if ($csid <= 0 || ! $date || $cnt <= 0) { + if ($csid <= 0 || !$date || $cnt <= 0) { continue; } @@ -136,7 +138,7 @@ class HomeworkTrackingService } $j = $baseIndex; - while ($j >= 0 && ! empty($eventDays[$sundays[$j]])) { + while ($j >= 0 && !empty($eventDays[$sundays[$j]])) { $j--; } if ($j < 0) { @@ -175,7 +177,7 @@ class HomeworkTrackingService if ($sid <= 0) { continue; } - if (! isset($bySection[$sid])) { + if (!isset($bySection[$sid])) { $bySection[$sid] = [ 'class_section_id' => $sid, 'class_id' => (int) ($row->class_id ?? 0), @@ -184,7 +186,7 @@ class HomeworkTrackingService 'tas' => [], ]; } - $name = trim((string) ($row->firstname ?? '').' '.(string) ($row->lastname ?? '')); + $name = trim((string) ($row->firstname ?? '') . ' ' . (string) ($row->lastname ?? '')); $pos = strtolower((string) ($row->position ?? '')); if ($name !== '') { if ($pos === 'main') { @@ -200,23 +202,15 @@ class HomeworkTrackingService $ai = (int) ($a['class_id'] ?? 0); $bi = (int) ($b['class_id'] ?? 0); $order = function (int $cid): int { - if ($cid === 13) { - return 0; - } - if ($cid >= 1 && $cid <= 11) { - return $cid; - } - if ($cid === 12) { - return 99; - } - + if ($cid === 13) return 0; + if ($cid >= 1 && $cid <= 11) return $cid; + if ($cid === 12) return 99; return 200 + $cid; }; $cmp = $order($ai) <=> $order($bi); if ($cmp !== 0) { return $cmp; } - return strnatcasecmp($a['class_section_name'] ?? '', $b['class_section_name'] ?? ''); }); diff --git a/app/Services/Grading/Policy/GradingPolicyResolver.php b/app/Services/Grading/Policy/GradingPolicyResolver.php index bf7b3ad6..a4b6501f 100644 --- a/app/Services/Grading/Policy/GradingPolicyResolver.php +++ b/app/Services/Grading/Policy/GradingPolicyResolver.php @@ -7,17 +7,14 @@ use App\Models\Configuration; class GradingPolicyResolver { public const LEGACY_MODE = 'legacy'; - public const STRONG_MODE = 'strong'; - public const LEGACY_VERSION = 'legacy_v1'; - public const STRONG_VERSION = 'strong_v1'; public function calculationMode(?int $classSectionId = null, ?string $semester = null, ?string $schoolYear = null): string { $enabled = strtolower((string) (Configuration::getConfig('strong_grading_enabled') ?? '')); - if (! in_array($enabled, ['1', 'true', 'yes', 'on'], true)) { + if (!in_array($enabled, ['1', 'true', 'yes', 'on'], true)) { return self::LEGACY_MODE; } @@ -27,7 +24,6 @@ class GradingPolicyResolver } $ids = array_filter(array_map('trim', explode(',', $allowedSections)), fn ($v) => $v !== ''); - return $classSectionId !== null && in_array((string) $classSectionId, $ids, true) ? self::STRONG_MODE : self::LEGACY_MODE; diff --git a/app/Services/Grading/StrongCategoryAverageCalculator.php b/app/Services/Grading/StrongCategoryAverageCalculator.php index 54f2bddf..4b390d29 100644 --- a/app/Services/Grading/StrongCategoryAverageCalculator.php +++ b/app/Services/Grading/StrongCategoryAverageCalculator.php @@ -31,19 +31,16 @@ class StrongCategoryAverageCalculator if ($status === 'pending' || $status === '') { $pending[] = $row; - continue; } if (in_array($status, ['excused', 'not_assigned'], true)) { $excluded[] = $row; - continue; } if ($status === 'missing') { $included[] = 0.0; - continue; } diff --git a/app/Services/Grading/Validation/GradebookFinalizationValidator.php b/app/Services/Grading/Validation/GradebookFinalizationValidator.php index 776cf6d6..f9510a66 100644 --- a/app/Services/Grading/Validation/GradebookFinalizationValidator.php +++ b/app/Services/Grading/Validation/GradebookFinalizationValidator.php @@ -15,7 +15,7 @@ class GradebookFinalizationValidator $errors = []; foreach ($this->scoreTables() as $table => $meta) { - if (! DB::getSchemaBuilder()->hasTable($table)) { + if (!DB::getSchemaBuilder()->hasTable($table)) { continue; } diff --git a/app/Services/Grading/Validation/ScoreValueValidator.php b/app/Services/Grading/Validation/ScoreValueValidator.php index 1c72c6f3..2141fb16 100644 --- a/app/Services/Grading/Validation/ScoreValueValidator.php +++ b/app/Services/Grading/Validation/ScoreValueValidator.php @@ -16,7 +16,7 @@ class ScoreValueValidator $max = $this->normalizeMaxPoints($maxPoints, $label); - if (! is_numeric($value)) { + if (!is_numeric($value)) { throw new InvalidArgumentException("{$label} must be numeric."); } @@ -34,7 +34,6 @@ class ScoreValueValidator if ($max <= 0) { throw new InvalidArgumentException("{$label} max points must be greater than 0."); } - return $max; } diff --git a/app/Services/Incidents/CurrentIncidentService.php b/app/Services/Incidents/CurrentIncidentService.php index ee0f08ef..9d1261f6 100644 --- a/app/Services/Incidents/CurrentIncidentService.php +++ b/app/Services/Incidents/CurrentIncidentService.php @@ -11,7 +11,9 @@ use Illuminate\Support\Facades\DB; class CurrentIncidentService { - public function __construct(private IncidentLookupService $lookup) {} + public function __construct(private IncidentLookupService $lookup) + { + } public function listCurrent(): array { @@ -21,7 +23,7 @@ class CurrentIncidentService $updaterIds = []; foreach ($incidents as $incident) { foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) { - if (! empty($incident[$key])) { + if (!empty($incident[$key])) { $updaterIds[] = (int) $incident[$key]; } } @@ -31,7 +33,7 @@ class CurrentIncidentService foreach ($incidents as &$incident) { foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) { $id = (int) ($incident[$key] ?? 0); - $incident[$key.'_name'] = $id > 0 ? ($updaterMap[$id] ?? null) : null; + $incident[$key . '_name'] = $id > 0 ? ($updaterMap[$id] ?? null) : null; } } unset($incident); @@ -60,7 +62,7 @@ class CurrentIncidentService ->get() ->map(fn ($student) => [ 'id' => (int) $student->id, - 'name' => trim((string) $student->firstname.' '.(string) $student->lastname), + 'name' => trim((string) $student->firstname . ' ' . (string) $student->lastname), ]) ->all(); } @@ -75,7 +77,7 @@ class CurrentIncidentService $grade = (string) $payload['grade']; $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return [ 'ok' => false, 'message' => 'Student not found.', @@ -119,7 +121,7 @@ class CurrentIncidentService $incident = CurrentIncident::query()->create([ 'student_id' => $student->id, - 'student_name' => trim((string) $student->firstname.' '.(string) $student->lastname), + 'student_name' => trim((string) $student->firstname . ' ' . (string) $student->lastname), 'grade' => $grade, 'incident' => $incidentType, 'incident_datetime' => $currentDateTime, @@ -147,7 +149,7 @@ class CurrentIncidentService public function closeIncident(int $incidentId, string $closeDescription, ?string $actionTaken, int $userId): array { $incident = CurrentIncident::query()->find($incidentId); - if (! $incident) { + if (!$incident) { return ['ok' => false, 'message' => 'Incident not found.']; } @@ -169,7 +171,7 @@ class CurrentIncidentService public function cancelIncident(int $incidentId, ?string $cancelDescription, ?string $actionTaken, int $userId): array { $incident = CurrentIncident::query()->find($incidentId); - if (! $incident) { + if (!$incident) { return ['ok' => false, 'message' => 'Incident not found.']; } @@ -226,6 +228,6 @@ class CurrentIncidentService return $append; } - return $existing.PHP_EOL.$append; + return $existing . PHP_EOL . $append; } } diff --git a/app/Services/Incidents/IncidentAnalysisService.php b/app/Services/Incidents/IncidentAnalysisService.php index 48d8aef8..768b93e7 100644 --- a/app/Services/Incidents/IncidentAnalysisService.php +++ b/app/Services/Incidents/IncidentAnalysisService.php @@ -6,7 +6,9 @@ use App\Models\Incident; class IncidentAnalysisService { - public function __construct(private IncidentLookupService $lookup) {} + public function __construct(private IncidentLookupService $lookup) + { + } public function analyze(?string $schoolYear, ?string $semester): array { @@ -29,7 +31,7 @@ class IncidentAnalysisService foreach ($incidents as $incident) { $studentId = (string) ($incident['student_id'] ?? ''); $studentName = (string) ($incident['student_name'] ?? ''); - $studentKey = $studentId !== '' ? 'id:'.$studentId : 'name:'.strtolower(trim($studentName)); + $studentKey = $studentId !== '' ? 'id:' . $studentId : 'name:' . strtolower(trim($studentName)); $gradeValue = $incident['grade'] ?? ''; $gradeLabel = $gradeValue; @@ -37,7 +39,7 @@ class IncidentAnalysisService $gradeLabel = $gradeMap[(int) $gradeValue] ?? (string) $gradeValue; } - if (! isset($students[$studentKey])) { + if (!isset($students[$studentKey])) { $students[$studentKey] = [ 'student_id' => $studentId, 'student_name' => $studentName, @@ -82,7 +84,6 @@ class IncidentAnalysisService if ($a['total'] === $b['total']) { return strcasecmp($a['student_name'], $b['student_name']); } - return $b['total'] <=> $a['total']; }); diff --git a/app/Services/Incidents/IncidentHistoryService.php b/app/Services/Incidents/IncidentHistoryService.php index f22f7779..36af2499 100644 --- a/app/Services/Incidents/IncidentHistoryService.php +++ b/app/Services/Incidents/IncidentHistoryService.php @@ -6,7 +6,9 @@ use App\Models\Incident; class IncidentHistoryService { - public function __construct(private IncidentLookupService $lookup) {} + public function __construct(private IncidentLookupService $lookup) + { + } public function history(?string $schoolYear, ?string $semester): array { @@ -33,7 +35,7 @@ class IncidentHistoryService $updaterIds = []; foreach ($incidents as $incident) { foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) { - if (! empty($incident[$key])) { + if (!empty($incident[$key])) { $updaterIds[] = (int) $incident[$key]; } } @@ -44,7 +46,7 @@ class IncidentHistoryService foreach ($incidents as &$incident) { foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) { $id = (int) ($incident[$key] ?? 0); - $incident[$key.'_name'] = $id > 0 ? ($updaterMap[$id] ?? null) : null; + $incident[$key . '_name'] = $id > 0 ? ($updaterMap[$id] ?? null) : null; } $gradeValue = $incident['grade'] ?? ''; diff --git a/app/Services/Incidents/IncidentLookupService.php b/app/Services/Incidents/IncidentLookupService.php index ca572ef4..81119202 100644 --- a/app/Services/Incidents/IncidentLookupService.php +++ b/app/Services/Incidents/IncidentLookupService.php @@ -4,7 +4,6 @@ namespace App\Services\Incidents; use App\Models\ClassSection; use App\Models\StudentClass; -use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Facades\DB; class IncidentLookupService @@ -73,7 +72,7 @@ class IncidentLookupService ->select('id', 'firstname', 'lastname') ->whereIn('id', $userIds) ->get() - ->map(fn ($row) => $row instanceof Arrayable ? $row->toArray() : (array) $row) + ->map(fn ($row) => $row instanceof \Illuminate\Contracts\Support\Arrayable ? $row->toArray() : (array) $row) ->all(); $map = []; @@ -82,8 +81,8 @@ class IncidentLookupService if ($id === null) { continue; } - $name = trim((string) ($row['firstname'] ?? '').' '.(string) ($row['lastname'] ?? '')); - $map[(int) $id] = $name !== '' ? $name : ('User #'.$id); + $name = trim((string) ($row['firstname'] ?? '') . ' ' . (string) ($row['lastname'] ?? '')); + $map[(int) $id] = $name !== '' ? $name : ('User #' . $id); } return $map; diff --git a/app/Services/Inventory/InventoryCategoryService.php b/app/Services/Inventory/InventoryCategoryService.php index 69a513b5..96d9f2b1 100644 --- a/app/Services/Inventory/InventoryCategoryService.php +++ b/app/Services/Inventory/InventoryCategoryService.php @@ -3,6 +3,7 @@ namespace App\Services\Inventory; use App\Models\InventoryCategory; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; class InventoryCategoryService @@ -15,7 +16,6 @@ class InventoryCategoryService if ($type) { $query->where('type', $this->normalizeType($type)); } - return $query->get()->toArray(); } @@ -37,8 +37,7 @@ class InventoryCategoryService try { $category = InventoryCategory::query()->create($payload); } catch (\Throwable $e) { - Log::error('Inventory category create failed: '.$e->getMessage()); - + Log::error('Inventory category create failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to save category.']; } @@ -48,7 +47,7 @@ class InventoryCategoryService public function update(int $id, array $data): array { $category = InventoryCategory::query()->find($id); - if (! $category) { + if (!$category) { return ['ok' => false, 'message' => 'Category not found.']; } @@ -69,8 +68,7 @@ class InventoryCategoryService try { $category->update($payload); } catch (\Throwable $e) { - Log::error('Inventory category update failed: '.$e->getMessage()); - + Log::error('Inventory category update failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to save category.']; } @@ -80,15 +78,14 @@ class InventoryCategoryService public function delete(int $id): array { $category = InventoryCategory::query()->find($id); - if (! $category) { + if (!$category) { return ['ok' => false, 'message' => 'Category not found.']; } try { $category->delete(); } catch (\Throwable $e) { - Log::error('Inventory category delete failed: '.$e->getMessage()); - + Log::error('Inventory category delete failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to delete category.']; } @@ -132,7 +129,6 @@ class InventoryCategoryService private function normalizeType(?string $type): string { $type = strtolower((string) $type); - return in_array($type, $this->types, true) ? $type : 'office'; } } diff --git a/app/Services/Inventory/InventoryItemService.php b/app/Services/Inventory/InventoryItemService.php index 9805872b..aaa14c20 100644 --- a/app/Services/Inventory/InventoryItemService.php +++ b/app/Services/Inventory/InventoryItemService.php @@ -2,8 +2,8 @@ namespace App\Services\Inventory; -use App\Models\InventoryCategory; use App\Models\InventoryItem; +use App\Models\InventoryCategory; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; @@ -14,7 +14,8 @@ class InventoryItemService public function __construct( private InventoryContextService $context, private InventoryMovementService $movementService - ) {} + ) { + } public function list(array $filters = []): array { @@ -31,7 +32,7 @@ class InventoryItemService $builder->where('semester', $semester); } if ($q !== '') { - $builder->where('name', 'like', '%'.$q.'%'); + $builder->where('name', 'like', '%' . $q . '%'); } $items = $builder->orderBy('name')->get()->toArray(); @@ -61,7 +62,6 @@ class InventoryItemService public function find(int $id): ?array { $item = InventoryItem::query()->find($id); - return $item ? $item->toArray() : null; } @@ -78,12 +78,10 @@ class InventoryItemService } else { $this->movementService->recalcQuantity((int) $item->id); } - return ['ok' => true, 'item' => $item->toArray()]; }); } catch (\Throwable $e) { - Log::error('Inventory item create failed: '.$e->getMessage()); - + Log::error('Inventory item create failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to create item.']; } } @@ -91,7 +89,7 @@ class InventoryItemService public function update(int $id, array $data, ?int $userId = null): array { $item = InventoryItem::query()->find($id); - if (! $item) { + if (!$item) { return ['ok' => false, 'message' => 'Item not found.']; } @@ -101,8 +99,7 @@ class InventoryItemService try { $item->update($payload); } catch (\Throwable $e) { - Log::error('Inventory item update failed: '.$e->getMessage()); - + Log::error('Inventory item update failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to update item.']; } @@ -112,15 +109,14 @@ class InventoryItemService public function delete(int $id): array { $item = InventoryItem::query()->find($id); - if (! $item) { + if (!$item) { return ['ok' => false, 'message' => 'Item not found.']; } try { $item->delete(); } catch (\Throwable $e) { - Log::error('Inventory item delete failed: '.$e->getMessage()); - + Log::error('Inventory item delete failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to delete item.']; } @@ -130,7 +126,7 @@ class InventoryItemService public function auditClassroom(int $itemId, array $data, ?int $userId = null): array { $item = InventoryItem::query()->find($itemId); - if (! $item || $item->type !== 'classroom') { + if (!$item || $item->type !== 'classroom') { return ['ok' => false, 'message' => 'Invalid classroom item.']; } @@ -163,7 +159,7 @@ class InventoryItemService $totalIn += -$deltaMiss; } - if ($totalOut > 0 && ! $this->movementService->recordMovement($itemId, -$totalOut, 'out', 'Audit: loss/missing increased')) { + if ($totalOut > 0 && !$this->movementService->recordMovement($itemId, -$totalOut, 'out', 'Audit: loss/missing increased')) { return ['ok' => false, 'message' => 'Not enough stock to apply audit.']; } if ($totalIn > 0) { @@ -186,7 +182,7 @@ class InventoryItemService public function adjustStock(int $itemId, array $data, ?int $userId = null): array { $item = InventoryItem::query()->find($itemId); - if (! $item) { + if (!$item) { return ['ok' => false, 'message' => 'Item not found.']; } @@ -203,7 +199,7 @@ class InventoryItemService $type = ($mode === 'out') ? 'out' : (($mode === 'in') ? 'in' : 'adjust'); $ok = $this->movementService->recordMovement($itemId, $delta, $type, $reason, $note, null, null, $userId); - if (! $ok) { + if (!$ok) { return ['ok' => false, 'message' => 'Not enough stock to apply adjustment.']; } @@ -246,7 +242,6 @@ class InventoryItemService private function normalizeType(?string $type): string { $type = strtolower((string) $type); - return in_array($type, $this->types, true) ? $type : 'classroom'; } @@ -272,9 +267,8 @@ class InventoryItemService } else { $out = []; foreach ($ids as $id) { - $out[$id] = 'User #'.$id; + $out[$id] = 'User #' . $id; } - return $out; } @@ -282,9 +276,8 @@ class InventoryItemService $map = []; foreach ($rows as $r) { $disp = trim((string) ($r->display_name ?? '')); - $map[(int) $r->id] = $disp !== '' ? $disp : ('User #'.$r->id); + $map[(int) $r->id] = $disp !== '' ? $disp : ('User #' . $r->id); } - return $map; } @@ -304,7 +297,7 @@ class InventoryItemService ->all(); $currentYear = $this->context->schoolYear(); - if ($currentYear && ! in_array($currentYear, $years, true)) { + if ($currentYear && !in_array($currentYear, $years, true)) { array_unshift($years, $currentYear); } diff --git a/app/Services/Inventory/InventoryMovementService.php b/app/Services/Inventory/InventoryMovementService.php index 7bc55fa2..daa9e524 100644 --- a/app/Services/Inventory/InventoryMovementService.php +++ b/app/Services/Inventory/InventoryMovementService.php @@ -9,7 +9,9 @@ use Illuminate\Support\Facades\Log; class InventoryMovementService { - public function __construct(private InventoryContextService $context) {} + public function __construct(private InventoryContextService $context) + { + } public function list(array $filters = []): array { @@ -49,7 +51,7 @@ class InventoryMovementService $qtyChange = (int) ($data['qty_change'] ?? 0); $item = InventoryItem::query()->find($itemId); - if (! $item) { + if (!$item) { return ['ok' => false, 'message' => 'Selected item not found.']; } @@ -76,8 +78,7 @@ class InventoryMovementService InventoryMovement::query()->create($payload); $this->recalcQuantity($itemId); } catch (\Throwable $e) { - Log::error('Inventory movement create failed: '.$e->getMessage()); - + Log::error('Inventory movement create failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Could not save movement.']; } @@ -87,7 +88,7 @@ class InventoryMovementService public function update(int $id, array $data): array { $movement = InventoryMovement::query()->find($id); - if (! $movement) { + if (!$movement) { return ['ok' => false, 'message' => 'Movement not found.']; } @@ -117,8 +118,7 @@ class InventoryMovementService $movement->update($payload); $this->recalcQuantity($itemId); } catch (\Throwable $e) { - Log::error('Inventory movement update failed: '.$e->getMessage()); - + Log::error('Inventory movement update failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Could not update movement.']; } @@ -128,7 +128,7 @@ class InventoryMovementService public function delete(int $id): array { $movement = InventoryMovement::query()->find($id); - if (! $movement) { + if (!$movement) { return ['ok' => false, 'message' => 'Movement not found.']; } @@ -139,8 +139,7 @@ class InventoryMovementService $this->recalcQuantity($itemId); } } catch (\Throwable $e) { - Log::error('Inventory movement delete failed: '.$e->getMessage()); - + Log::error('Inventory movement delete failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Could not delete movement.']; } @@ -170,8 +169,7 @@ class InventoryMovementService $this->recalcQuantity($itemId); } } catch (\Throwable $e) { - Log::error('Inventory movement bulk delete failed: '.$e->getMessage()); - + Log::error('Inventory movement bulk delete failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Bulk delete failed.']; } @@ -190,7 +188,7 @@ class InventoryMovementService ): bool { $isInitial = ($type === 'initial'); - if (! $isInitial) { + if (!$isInitial) { $this->ensureInitialMovement($itemId); $this->ensureInitialMovementForYear($itemId, $this->context->schoolYear()); $this->recalcQuantity($itemId); @@ -219,7 +217,6 @@ class InventoryMovementService ]); $this->recalcQuantity($itemId); - return true; } @@ -236,7 +233,7 @@ class InventoryMovementService } $item = InventoryItem::query()->select('id', 'type', 'quantity', 'needs_repair_qty', 'good_qty')->find($itemId); - if (! $item) { + if (!$item) { return; } @@ -253,7 +250,7 @@ class InventoryMovementService } } - if (! empty($updates)) { + if (!empty($updates)) { $item->update($updates); } } @@ -284,7 +281,7 @@ class InventoryMovementService ->where('school_year', $schoolYear) ->exists(); - if (! $hasAnyThisYear) { + if (!$hasAnyThisYear) { $onHand = (int) (InventoryItem::query()->where('id', $itemId)->value('quantity') ?? 0); InventoryMovement::query()->create([ 'item_id' => $itemId, @@ -293,7 +290,6 @@ class InventoryMovementService 'school_year' => $schoolYear, 'semester' => $this->context->semester() ?: null, ]); - return; } @@ -303,7 +299,7 @@ class InventoryMovementService ->where('movement_type', 'initial') ->exists(); - if (! $hasInitial) { + if (!$hasInitial) { $onHand = (int) (InventoryItem::query()->where('id', $itemId)->value('quantity') ?? 0); $netYear = (int) (InventoryMovement::query() ->where('item_id', $itemId) @@ -326,14 +322,12 @@ class InventoryMovementService if (in_array($movementType, ['out', 'distribution'], true) && $qtyChange > 0) { return -abs($qtyChange); } - return $qtyChange; } private function wouldGoNegative(int $itemId, int $delta): bool { $onHand = (int) (InventoryItem::query()->where('id', $itemId)->value('quantity') ?? 0); - return $onHand + $delta < 0; } @@ -342,7 +336,6 @@ class InventoryMovementService if ($val === null || $val === '' || $val === '0') { return null; } - return (int) $val; } } diff --git a/app/Services/Inventory/InventorySummaryService.php b/app/Services/Inventory/InventorySummaryService.php index 5254f847..6d91e5e9 100644 --- a/app/Services/Inventory/InventorySummaryService.php +++ b/app/Services/Inventory/InventorySummaryService.php @@ -7,7 +7,9 @@ use Illuminate\Support\Facades\DB; class InventorySummaryService { - public function __construct(private InventoryContextService $context) {} + public function __construct(private InventoryContextService $context) + { + } public function summary(string $type, ?string $schoolYear): array { @@ -22,7 +24,7 @@ class InventorySummaryService $itemIds = array_map(static fn ($i) => (int) ($i['id'] ?? 0), $items); $agg = []; - if (! empty($itemIds)) { + if (!empty($itemIds)) { $qb = DB::table('inventory_movements') ->selectRaw('item_id, SUM(CASE WHEN qty_change>0 THEN qty_change ELSE 0 END) AS received, @@ -63,7 +65,7 @@ class InventorySummaryService ->leftJoin('users as u', 'u.id', '=', 'i.updated_by') ->orderBy('i.name'); - if (! $isAllYears) { + if (!$isAllYears) { $qbItems->where('i.school_year', $selectedYear); } @@ -85,7 +87,7 @@ class InventorySummaryService 'variance' => 0, ]; - if (! empty($items)) { + if (!empty($items)) { $itemIds = array_map('intval', array_column($items, 'id')); $aggById = []; $qb = DB::table('inventory_movements as m') @@ -100,7 +102,7 @@ class InventorySummaryService ->whereIn('m.item_id', $itemIds) ->groupBy('m.item_id'); - if (! $isAllYears) { + if (!$isAllYears) { $qb->where('m.school_year', $selectedYear); } @@ -180,7 +182,7 @@ class InventorySummaryService ->all(); $currentYear = $this->context->schoolYear(); - if ($currentYear && ! in_array($currentYear, $years, true)) { + if ($currentYear && !in_array($currentYear, $years, true)) { array_unshift($years, $currentYear); } diff --git a/app/Services/Inventory/InventoryTeacherDistributionService.php b/app/Services/Inventory/InventoryTeacherDistributionService.php index 25501c9c..e5b76634 100644 --- a/app/Services/Inventory/InventoryTeacherDistributionService.php +++ b/app/Services/Inventory/InventoryTeacherDistributionService.php @@ -9,18 +9,20 @@ use App\Models\StudentClass; use App\Models\TeacherClass; use App\Models\User; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; class InventoryTeacherDistributionService { public function __construct( private InventoryContextService $context, private InventoryMovementService $movementService - ) {} + ) { + } public function formData(int $userId, ?int $classSectionId, ?int $itemId): array { $ctx = $this->buildTeacherClassContext($userId); - if (! $ctx['ok']) { + if (!$ctx['ok']) { return $ctx; } @@ -31,7 +33,7 @@ class InventoryTeacherDistributionService : (int) ($classSectionId ?? ($ctx['defaultClassSectionId'] ?? 0)); $classID = null; - if (! empty($selectedClassId)) { + if (!empty($selectedClassId)) { $classID = ClassSection::getClassId($selectedClassId); $classID = $classID !== null ? (int) $classID : null; } @@ -41,7 +43,7 @@ class InventoryTeacherDistributionService ->leftJoin('inventory_categories as c', 'c.id', '=', 'i.category_id') ->where('i.type', 'book'); - if (! empty($classID)) { + if (!empty($classID)) { $builder->where(function ($q) use ($classID) { $q->where(function ($inner) use ($classID) { $inner->whereNotNull('c.grade_min') @@ -66,34 +68,27 @@ class InventoryTeacherDistributionService $name = $r['category_name'] ?? 'Uncategorized'; $gmin = $r['grade_min'] ?? null; $gmax = $r['grade_max'] ?? null; - if ($gmin === null && $gmax === null) { - return $name; - } - if ($gmin !== null && $gmax !== null) { - return $name.' (G'.(int) $gmin.'–G'.(int) $gmax.')'; - } - if ($gmin !== null) { - return $name.' (G'.(int) $gmin.'+)'; - } - - return $name.' (≤G'.(int) $gmax.')'; + if ($gmin === null && $gmax === null) return $name; + if ($gmin !== null && $gmax !== null) return $name . ' (G' . (int) $gmin . '–G' . (int) $gmax . ')'; + if ($gmin !== null) return $name . ' (G' . (int) $gmin . '+)'; + return $name . ' (≤G' . (int) $gmax . ')'; }; $booksGrouped = []; foreach ($rows as $r) { $catId = (int) ($r['category_id'] ?? 0); - if (! isset($booksGrouped[$catId])) { + if (!isset($booksGrouped[$catId])) { $booksGrouped[$catId] = [ 'label' => $labelFor($r), 'items' => [], ]; } $display = $r['name']; - if (! empty($r['isbn'])) { - $display .= ' — ISBN '.$r['isbn']; + if (!empty($r['isbn'])) { + $display .= ' — ISBN ' . $r['isbn']; } - if (! empty($r['edition'])) { - $display .= ' ('.$r['edition'].')'; + if (!empty($r['edition'])) { + $display .= ' (' . $r['edition'] . ')'; } $booksGrouped[$catId]['items'][] = [ @@ -128,9 +123,7 @@ class InventoryTeacherDistributionService ->all(); foreach ($rowsHist as $r) { $sid = (int) ($r['student_id'] ?? 0); - if ($sid) { - $already[$sid] = (int) ($r['qty'] ?? 0); - } + if ($sid) $already[$sid] = (int) ($r['qty'] ?? 0); } } @@ -161,7 +154,7 @@ class InventoryTeacherDistributionService public function distribute(int $userId, array $payload): array { $ctx = $this->buildTeacherClassContext($userId); - if (! $ctx['ok']) { + if (!$ctx['ok']) { return $ctx; } @@ -175,12 +168,12 @@ class InventoryTeacherDistributionService ? (int) $classIds[0] : (in_array($postedClassId, $classIds, true) ? $postedClassId : 0); - if (! $classSectionId) { + if (!$classSectionId) { return ['ok' => false, 'message' => 'Invalid class selection.']; } $book = InventoryItem::query()->find($itemId); - if (! $book || $book->type !== 'book') { + if (!$book || $book->type !== 'book') { return ['ok' => false, 'message' => 'Invalid book.']; } @@ -188,9 +181,7 @@ class InventoryTeacherDistributionService $validIds = []; foreach ($students as $st) { $sid = $st['student_id'] ?? ($st['id'] ?? null); - if ($sid) { - $validIds[(int) $sid] = true; - } + if ($sid) $validIds[(int) $sid] = true; } $selectedIds = array_values(array_filter($selectedIds, fn ($sid) => isset($validIds[$sid]))); @@ -209,9 +200,7 @@ class InventoryTeacherDistributionService ->all(); foreach ($rows as $r) { $sid = (int) ($r['student_id'] ?? 0); - if ($sid) { - $already[$sid] = (int) ($r['qty'] ?? 0); - } + if ($sid) $already[$sid] = (int) ($r['qty'] ?? 0); } $toGive = []; @@ -254,7 +243,7 @@ class InventoryTeacherDistributionService } $user = User::query()->find($userId); - if (! $user) { + if (!$user) { return ['ok' => false, 'message' => 'User not found.']; } @@ -264,13 +253,13 @@ class InventoryTeacherDistributionService ->pluck('r.name') ->toArray(); - if (! in_array('teacher', $roles, true) && ! in_array('teacher_assistant', $roles, true)) { + if (!in_array('teacher', $roles, true) && !in_array('teacher_assistant', $roles, true)) { return ['ok' => false, 'message' => 'Access denied.']; } $classSectionIds = array_column($classes, 'class_section_id'); $studentsData = []; - if (! empty($classSectionIds)) { + if (!empty($classSectionIds)) { $students = StudentClass::getStudentsByClassSectionIds($classSectionIds); foreach ($students as $student) { $studentsData[$student['class_section_id']][] = $student; @@ -289,7 +278,7 @@ class InventoryTeacherDistributionService $taUser = User::query()->find($ta['teacher_id'] ?? 0); if ($taUser) { $csid = $ta['class_section_id']; - $taNames[$csid][] = trim(($taUser->firstname ?? '').' '.($taUser->lastname ?? '')); + $taNames[$csid][] = trim(($taUser->firstname ?? '') . ' ' . ($taUser->lastname ?? '')); } } diff --git a/app/Services/Inventory/SupplierService.php b/app/Services/Inventory/SupplierService.php index 1e6a8fde..a852d638 100644 --- a/app/Services/Inventory/SupplierService.php +++ b/app/Services/Inventory/SupplierService.php @@ -13,9 +13,9 @@ class SupplierService $query = Supplier::query(); if ($q !== '') { $query->where(function ($builder) use ($q) { - $builder->where('name', 'like', '%'.$q.'%') - ->orWhere('email', 'like', '%'.$q.'%') - ->orWhere('phone', 'like', '%'.$q.'%'); + $builder->where('name', 'like', '%' . $q . '%') + ->orWhere('email', 'like', '%' . $q . '%') + ->orWhere('phone', 'like', '%' . $q . '%'); }); } @@ -37,8 +37,7 @@ class SupplierService try { $supplier = Supplier::query()->create($this->payload($data)); } catch (\Throwable $e) { - Log::error('Supplier create failed: '.$e->getMessage()); - + Log::error('Supplier create failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to save supplier.']; } @@ -48,15 +47,14 @@ class SupplierService public function update(int $id, array $data): array { $supplier = Supplier::query()->find($id); - if (! $supplier) { + if (!$supplier) { return ['ok' => false, 'message' => 'Supplier not found.']; } try { $supplier->update($this->payload($data)); } catch (\Throwable $e) { - Log::error('Supplier update failed: '.$e->getMessage()); - + Log::error('Supplier update failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to update supplier.']; } @@ -66,15 +64,14 @@ class SupplierService public function delete(int $id): array { $supplier = Supplier::query()->find($id); - if (! $supplier) { + if (!$supplier) { return ['ok' => false, 'message' => 'Supplier not found.']; } try { $supplier->delete(); } catch (\Throwable $e) { - Log::error('Supplier delete failed: '.$e->getMessage()); - + Log::error('Supplier delete failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to delete supplier.']; } diff --git a/app/Services/Inventory/SupplyCategoryService.php b/app/Services/Inventory/SupplyCategoryService.php index 273553a3..b435ea67 100644 --- a/app/Services/Inventory/SupplyCategoryService.php +++ b/app/Services/Inventory/SupplyCategoryService.php @@ -19,8 +19,7 @@ class SupplyCategoryService 'name' => (string) ($data['name'] ?? ''), ]); } catch (\Throwable $e) { - Log::error('Supply category create failed: '.$e->getMessage()); - + Log::error('Supply category create failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to save category.']; } @@ -30,15 +29,14 @@ class SupplyCategoryService public function update(int $id, array $data): array { $category = SupplyCategory::query()->find($id); - if (! $category) { + if (!$category) { return ['ok' => false, 'message' => 'Category not found.']; } try { $category->update(['name' => (string) ($data['name'] ?? '')]); } catch (\Throwable $e) { - Log::error('Supply category update failed: '.$e->getMessage()); - + Log::error('Supply category update failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to update category.']; } @@ -48,15 +46,14 @@ class SupplyCategoryService public function delete(int $id): array { $category = SupplyCategory::query()->find($id); - if (! $category) { + if (!$category) { return ['ok' => false, 'message' => 'Category not found.']; } try { $category->delete(); } catch (\Throwable $e) { - Log::error('Supply category delete failed: '.$e->getMessage()); - + Log::error('Supply category delete failed: ' . $e->getMessage()); return ['ok' => false, 'message' => 'Failed to delete category.']; } diff --git a/app/Services/Invoices/InvoiceConfigService.php b/app/Services/Invoices/InvoiceConfigService.php index cff9bca1..1ccb9cc7 100644 --- a/app/Services/Invoices/InvoiceConfigService.php +++ b/app/Services/Invoices/InvoiceConfigService.php @@ -19,7 +19,6 @@ class InvoiceConfigService public function getDueDate(): ?string { $value = Configuration::getConfig('due_date'); - return $value ? (string) $value : null; } @@ -46,7 +45,7 @@ class InvoiceConfigService public function getRefundDeadline(): ?string { $value = Configuration::getConfig('refund_deadline'); - if (! $value) { + if (!$value) { return null; } diff --git a/app/Services/Invoices/InvoiceGenerationService.php b/app/Services/Invoices/InvoiceGenerationService.php index 7ed4f7dd..ddc5c5db 100644 --- a/app/Services/Invoices/InvoiceGenerationService.php +++ b/app/Services/Invoices/InvoiceGenerationService.php @@ -18,7 +18,8 @@ class InvoiceGenerationService public function __construct( private InvoiceConfigService $config, private InvoiceTuitionService $tuitionService - ) {} + ) { + } public function generateInvoice(int $parentId, ?string $schoolYear = null): array { @@ -63,13 +64,11 @@ class InvoiceGenerationService $registeredKids = array_values(array_filter($registeredKids, function ($student) use ($schoolYear) { $sid = (int) ($student['student_id'] ?? 0); - return $sid > 0 && StudentClass::hasNonEventAssignment($sid, $schoolYear); })); $withdrawnKids = array_values(array_filter($withdrawnKids, function ($student) use ($schoolYear) { $sid = (int) ($student['student_id'] ?? 0); - return $sid > 0 && StudentClass::hasNonEventAssignment($sid, $schoolYear); })); @@ -84,7 +83,7 @@ class InvoiceGenerationService $this->recalculateAndUpdateDiscount($parentId, $schoolYear, $tuitionFee, $enrollments); - $refundPaid = (new Refund)->getTotalApprovedRefundByParentIdAndSchoolYear($parentId, $schoolYear); + $refundPaid = (new Refund())->getTotalApprovedRefundByParentIdAndSchoolYear($parentId, $schoolYear); $totalPaid = Payment::getTotalPaidByParentId($parentId, $schoolYear); $totalAmount = max(0.0, (float) $tuitionFee) + (float) $eventChargeTotal; @@ -94,9 +93,9 @@ class InvoiceGenerationService $updatedIds = []; $insertId = null; - if (! empty($existingInvoices)) { + if (!empty($existingInvoices)) { foreach ($existingInvoices as $invoice) { - if (! isset($invoice['id'])) { + if (!isset($invoice['id'])) { continue; } @@ -128,14 +127,14 @@ class InvoiceGenerationService } else { $schoolId = User::getSchoolIdByUserId($parentId); $invoiceNumber = $schoolId - ? ('INV-'.$schoolId.'-'.uniqid()) + ? ('INV-' . $schoolId . '-' . uniqid()) : uniqid('INV-'); $issueUtc = (new DateTime('now', new DateTimeZone('UTC')))->format('Y-m-d H:i:s'); $dueUtc = null; $dueDate = $this->config->getDueDate(); - if (! empty($dueDate)) { - $dueLocal = new DateTime($dueDate.' 19:59:59', new DateTimeZone($this->config->getTimezone())); + if (!empty($dueDate)) { + $dueLocal = new DateTime($dueDate . ' 19:59:59', new DateTimeZone($this->config->getTimezone())); $dueLocal->setTimezone(new DateTimeZone('UTC')); $dueUtc = $dueLocal->format('Y-m-d H:i:s'); } @@ -181,7 +180,7 @@ class InvoiceGenerationService } foreach ($invoices as $invoice) { - if (! isset($invoice['id'])) { + if (!isset($invoice['id'])) { continue; } @@ -194,7 +193,7 @@ class InvoiceGenerationService ->where('i.school_year', $schoolYear) ->first(); - if (! $discountUsage) { + if (!$discountUsage) { continue; } diff --git a/app/Services/Invoices/InvoiceGradeService.php b/app/Services/Invoices/InvoiceGradeService.php index 7609503a..41d54c1e 100644 --- a/app/Services/Invoices/InvoiceGradeService.php +++ b/app/Services/Invoices/InvoiceGradeService.php @@ -4,12 +4,13 @@ namespace App\Services\Invoices; class InvoiceGradeService { - public function __construct(private int $gradeFee) {} + public function __construct(private int $gradeFee) + { + } public function isKindergarten(string $grade): bool { $g = strtolower(trim($grade)); - return in_array($g, ['KG', 'kg', 'k', 'kindergarten', 'k-g', 'k.g', 'k g'], true); } @@ -28,7 +29,6 @@ class InvoiceGradeService public function gradeLevelInt(string $grade): int { $gl = $this->getGradeLevel($grade); - return (int) ($gl['level'] ?? 0); } @@ -39,11 +39,10 @@ class InvoiceGradeService if ($num === 13) { return ['level' => 1, 'suffix' => '', 'classId' => 13]; } - return ['level' => $num, 'suffix' => '', 'classId' => null]; } - if (! is_string($grade)) { + if (!is_string($grade)) { return ['level' => 999, 'suffix' => '', 'classId' => null]; } @@ -64,7 +63,6 @@ class InvoiceGradeService if (preg_match('/^Y(?:OUTH)?(?:\s*(\d+))?$/', $g, $m)) { $n = isset($m[1]) && $m[1] !== '' ? max(1, (int) $m[1]) : 1; - return [ 'level' => $this->gradeFee + $n, 'suffix' => '', diff --git a/app/Services/Invoices/InvoiceManagementService.php b/app/Services/Invoices/InvoiceManagementService.php index d81a0886..b410ec7c 100644 --- a/app/Services/Invoices/InvoiceManagementService.php +++ b/app/Services/Invoices/InvoiceManagementService.php @@ -5,12 +5,15 @@ namespace App\Services\Invoices; use App\Models\Enrollment; use App\Models\Invoice; use App\Models\Student; +use App\Models\StudentClass; use App\Models\User; use Illuminate\Support\Facades\DB; class InvoiceManagementService { - public function __construct(private InvoiceConfigService $config) {} + public function __construct(private InvoiceConfigService $config) + { + } public function getManagementData(?string $schoolYear): array { @@ -44,7 +47,7 @@ class InvoiceManagementService ->all(); $parentData = [ - 'parent_name' => trim(($parent['firstname'] ?? '').' '.($parent['lastname'] ?? '')), + 'parent_name' => trim(($parent['firstname'] ?? '') . ' ' . ($parent['lastname'] ?? '')), 'parent_id' => (int) $parent['id'], 'enrolledKids' => [], 'withdrawnKids' => [], @@ -57,7 +60,7 @@ class InvoiceManagementService $invoices = Invoice::getInvoicesByParentId((int) $parent['id'], $schoolYear); foreach ($invoices as $invoice) { - if (! $invoice) { + if (!$invoice) { continue; } @@ -65,13 +68,13 @@ class InvoiceManagementService $parentData['last_updated'] = $invoice['updated_at'] ?? null; $parentData['invoice_id'] = $invoice['id'] ?? null; - if (! empty($invoice['issue_date'])) { + if (!empty($invoice['issue_date'])) { $tzName = $this->config->getTimezone(); $parentData['invoice_date'] = (new \DateTimeImmutable($invoice['issue_date'], new \DateTimeZone('UTC'))) ->setTimezone(new \DateTimeZone($tzName)) ->format('Y-m-d H:i:s'); } else { - $parentData['invoice_date'] = ! empty($invoice['updated_at']) + $parentData['invoice_date'] = !empty($invoice['updated_at']) ? date('Y-m-d H:i:s', strtotime($invoice['updated_at'])) : null; } @@ -112,7 +115,7 @@ class InvoiceManagementService foreach ($enrollments as $enrollment) { $kid = [ - 'name' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')), + 'name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')), 'grade' => $grade, 'tuition_fee' => (float) ($enrollment['tuition_fee'] ?? 0), ]; @@ -133,7 +136,7 @@ class InvoiceManagementService } } - if (! empty($parentData['enrolledKids']) || ! empty($parentData['withdrawnKids'])) { + if (!empty($parentData['enrolledKids']) || !empty($parentData['withdrawnKids'])) { $invoiceData[] = $parentData; } } diff --git a/app/Services/Invoices/InvoicePaymentService.php b/app/Services/Invoices/InvoicePaymentService.php index 51bb2275..ec1ad56c 100644 --- a/app/Services/Invoices/InvoicePaymentService.php +++ b/app/Services/Invoices/InvoicePaymentService.php @@ -8,7 +8,9 @@ use Illuminate\Support\Facades\DB; class InvoicePaymentService { - public function __construct(private InvoiceConfigService $config) {} + public function __construct(private InvoiceConfigService $config) + { + } public function getParentInvoiceSummary(int $parentId, ?string $schoolYear): array { @@ -24,9 +26,9 @@ class InvoicePaymentService ->all(); $selectedYear = $schoolYear ?: null; - if (! $selectedYear) { + if (!$selectedYear) { $hasCurrentYear = in_array($currentSchoolYear, array_column($schoolYears, 'school_year'), true); - $selectedYear = $hasCurrentYear ? $currentSchoolYear : (! empty($schoolYears) ? $schoolYears[0]['school_year'] : null); + $selectedYear = $hasCurrentYear ? $currentSchoolYear : (!empty($schoolYears) ? $schoolYears[0]['school_year'] : null); } $invoices = []; @@ -36,7 +38,7 @@ class InvoicePaymentService $invoiceIds = array_column($invoices, 'id'); $refunds = []; - if (! empty($invoiceIds)) { + if (!empty($invoiceIds)) { $refundResults = DB::table('refunds') ->selectRaw('invoice_id, COALESCE(SUM(refund_paid_amount),0) as refund_paid_amount') ->whereIn('invoice_id', $invoiceIds) @@ -52,7 +54,7 @@ class InvoicePaymentService } $lastPayments = []; - if (! empty($invoiceIds)) { + if (!empty($invoiceIds)) { $paymentResults = Payment::getPaymentsByInvoice($invoiceIds); foreach ($paymentResults as $payment) { $lastPayments[$payment['invoice_id']] = [ diff --git a/app/Services/Invoices/InvoicePdfService.php b/app/Services/Invoices/InvoicePdfService.php index a69482f1..ab47d5d6 100644 --- a/app/Services/Invoices/InvoicePdfService.php +++ b/app/Services/Invoices/InvoicePdfService.php @@ -9,6 +9,7 @@ use App\Models\Enrollment; use App\Models\EventCharges; use App\Models\Invoice; use App\Models\Payment; +use App\Models\Refund; use App\Models\Student; use App\Models\StudentClass; use App\Models\User; @@ -20,7 +21,8 @@ class InvoicePdfService public function __construct( private InvoiceConfigService $config, private InvoiceGradeService $grades - ) {} + ) { + } public function buildPdf(int $invoiceId): string { @@ -40,7 +42,7 @@ class InvoicePdfService private function prepareInvoiceData(int $invoiceId): array { $invoice = Invoice::query()->find($invoiceId); - if (! $invoice) { + if (!$invoice) { return ['error' => 'No invoice was generated. Please contact the school administration.']; } @@ -67,7 +69,7 @@ class InvoicePdfService $payments = $paymentsQuery->get()->map(fn ($r) => $r->toArray())->all(); $parent = User::query()->find($parentId); - if (! $parent) { + if (!$parent) { return ['error' => 'Parent associated with the invoice was not found.']; } @@ -87,7 +89,7 @@ class InvoicePdfService foreach ($enrollments as $enrollment) { $student = Student::query()->find($enrollment['student_id']); - if (! $student) { + if (!$student) { continue; } @@ -110,13 +112,11 @@ class InvoicePdfService $registeredKids = array_values(array_filter($registeredKids, function ($student) use ($schoolYear) { $sid = (int) ($student['student_id'] ?? 0); - return $sid > 0 && StudentClass::hasNonEventAssignment($sid, $schoolYear); })); $withdrawnKids = array_values(array_filter($withdrawnKids, function ($student) use ($schoolYear) { $sid = (int) ($student['student_id'] ?? 0); - return $sid > 0 && StudentClass::hasNonEventAssignment($sid, $schoolYear); })); @@ -148,10 +148,8 @@ class InvoicePdfService if ($isRegular) { $fee = $regularCount === 0 ? $firstFee : $secondFee; $regularCount++; - return $fee; } - return $youthFee; }; @@ -162,7 +160,7 @@ class InvoicePdfService $studentCharges[$student['student_id']] = ['unit_fee' => $unitFee, 'refund' => 0]; } - if (! $refundAllowed) { + if (!$refundAllowed) { foreach ($withdrawnKids as $student) { $gradeName = (string) ($student['grade'] ?? ''); $gradeLevel = $this->grades->gradeLevelInt($gradeName); @@ -175,7 +173,7 @@ class InvoicePdfService $studentIds = array_values(array_unique(array_map(static fn ($r) => (int) ($r['student_id'] ?? 0), array_merge($registeredKids, $withdrawnKids)))); $schoolIdMap = []; - if (! empty($studentIds)) { + if (!empty($studentIds)) { $rows = Student::query()->whereIn('id', $studentIds)->get(['id', 'school_id'])->all(); foreach ($rows as $row) { $schoolIdMap[(int) $row->id] = $row->school_id ?? 'N/A'; @@ -224,9 +222,9 @@ class InvoicePdfService $signed = abs($signed); } - $lineDate = ! empty($ac['created_at']) + $lineDate = !empty($ac['created_at']) ? date('Y-m-d', strtotime($ac['created_at'])) - : (! empty($invoice->created_at) ? local_date($invoice->created_at, 'Y-m-d') : local_date(utc_now(), 'Y-m-d')); + : (!empty($invoice->created_at) ? local_date($invoice->created_at, 'Y-m-d') : local_date(utc_now(), 'Y-m-d')); $desc = $ac['description'] ?? ''; if ($desc === '') { @@ -272,7 +270,7 @@ class InvoicePdfService $additionalChargesTotal = (float) ($data['additionalChargesTotal'] ?? 0); $refundsPaidTotal = (float) ($data['refundsPaidTotal'] ?? 0); - $pdf = new \FPDF; + $pdf = new \FPDF(); $pdf->AddPage(); $pdf->SetFont('Arial', 'B', 16); $pdf->Cell(0, 10, 'Invoice', 0, 1, 'C'); @@ -281,7 +279,7 @@ class InvoicePdfService $pdf->SetFont('Arial', 'B', 12); $pdf->Cell(40, 6, 'Parent Name:', 0, 0, 'L'); $pdf->SetFont('Arial', '', 12); - $pdf->Cell(0, 6, ($parent['firstname'] ?? '').' '.($parent['lastname'] ?? ''), 0, 1, 'L'); + $pdf->Cell(0, 6, ($parent['firstname'] ?? '') . ' ' . ($parent['lastname'] ?? ''), 0, 1, 'L'); $pdf->SetFont('Arial', 'B', 12); $pdf->Cell(40, 6, 'Invoice Number:', 0, 0, 'L'); @@ -308,7 +306,7 @@ class InvoicePdfService $tz = new \DateTimeZone($this->config->getTimezone()); $toLocal = function (?string $raw) use ($tz): \DateTimeImmutable { - if (! $raw) { + if (!$raw) { return new \DateTimeImmutable('now', $tz); } try { @@ -321,24 +319,24 @@ class InvoicePdfService foreach ($registeredKids as $student) { $id = $student['student_id']; $unit = (float) ($studentCharges[$id]['unit_fee'] ?? 0.0); - $name = $student['student_firstname'].' '.$student['student_lastname']; + $name = $student['student_firstname'] . ' ' . $student['student_lastname']; $gradeName = ClassSection::getClassSectionNameByClassId($student['grade']) ?? $student['grade']; - $push($toLocal($invoice['created_at'] ?? null), 'Registration of "'.$name.'" in '.$gradeName, $unit, 'registration'); + $push($toLocal($invoice['created_at'] ?? null), 'Registration of "' . $name . '" in ' . $gradeName, $unit, 'registration'); } foreach ($events as $event) { $studentName = 'N/A'; - if (! empty($event['student_id'])) { + if (!empty($event['student_id'])) { foreach ($students as $st) { if (($st['student_id'] ?? null) == $event['student_id']) { - $studentName = $st['student_firstname'].' '.$st['student_lastname']; + $studentName = $st['student_firstname'] . ' ' . $st['student_lastname']; break; } } } $amount = (float) ($event['charged'] ?? 0.0); $eventName = $event['event_name'] ?? 'Event'; - $push($toLocal($event['created_at'] ?? null), 'Event '.$eventName.' for "'.$studentName.'"', $amount, 'event'); + $push($toLocal($event['created_at'] ?? null), 'Event ' . $eventName . ' for "' . $studentName . '"', $amount, 'event'); } foreach ($additionalChargeLines as $line) { @@ -349,7 +347,7 @@ class InvoicePdfService foreach ($payments as $payment) { $amount = (float) ($payment['paid_amount'] ?? 0.0); $totalPaid += $amount; - $push($toLocal($payment['payment_date'] ?? null), 'Payment ('.($payment['payment_method'] ?? 'Payment').')', -$amount, 'payment'); + $push($toLocal($payment['payment_date'] ?? null), 'Payment (' . ($payment['payment_method'] ?? 'Payment') . ')', -$amount, 'payment'); } $totalDiscount = 0.0; @@ -379,7 +377,6 @@ class InvoicePdfService return $pa <=> $pb; } $cmp = $a['dt'] <=> $b['dt']; - return $cmp !== 0 ? $cmp : ($a['seq'] <=> $b['seq']); }); @@ -387,7 +384,7 @@ class InvoicePdfService foreach ($transactions as $t) { $pdf->Cell(30, 7, $t['dt']->format('m-d-Y'), 1); $pdf->Cell(130, 7, $t['description'], 1); - $pdf->Cell(30, 7, ($t['amount'] < 0 ? '-$' : '$').number_format(abs($t['amount']), 2), 1, 1, 'R'); + $pdf->Cell(30, 7, ($t['amount'] < 0 ? '-$' : '$') . number_format(abs($t['amount']), 2), 1, 1, 'R'); } $tuitionSubtotal = 0.0; @@ -409,38 +406,38 @@ class InvoicePdfService $pdf->SetFont('Arial', 'B', 12); $pdf->Cell(160, 7, 'Total Charges:', 0, 0, 'R'); $pdf->SetFont('Arial', '', 12); - $pdf->Cell(30, 7, '$'.number_format($totalAmount, 2), 0, 1, 'R'); + $pdf->Cell(30, 7, '$' . number_format($totalAmount, 2), 0, 1, 'R'); $pdf->SetFont('Arial', 'B', 12); $pdf->Cell(160, 7, 'Total Paid:', 0, 0, 'R'); $pdf->SetFont('Arial', '', 12); - $pdf->Cell(30, 7, '$'.number_format($totalPaid, 2), 0, 1, 'R'); + $pdf->Cell(30, 7, '$' . number_format($totalPaid, 2), 0, 1, 'R'); if ($totalDiscount > 0) { $pdf->SetFont('Arial', 'B', 12); $pdf->Cell(160, 7, 'Total Discount:', 0, 0, 'R'); $pdf->SetFont('Arial', '', 12); - $pdf->Cell(30, 7, '$'.number_format($totalDiscount, 2), 0, 1, 'R'); + $pdf->Cell(30, 7, '$' . number_format($totalDiscount, 2), 0, 1, 'R'); } if ($refundsPaidTotal > 0) { $pdf->SetFont('Arial', 'B', 12); $pdf->Cell(160, 7, 'Refunds Paid:', 0, 0, 'R'); $pdf->SetFont('Arial', '', 12); - $pdf->Cell(30, 7, '$'.number_format($refundsPaidTotal, 2), 0, 1, 'R'); + $pdf->Cell(30, 7, '$' . number_format($refundsPaidTotal, 2), 0, 1, 'R'); } $pdf->SetFont('Arial', 'B', 12); $pdf->Cell(160, 7, 'Balance Due:', 0, 0, 'R'); $pdf->SetFont('Arial', '', 12); - $pdf->Cell(30, 7, '$'.number_format($balance, 2), 0, 1, 'R'); + $pdf->Cell(30, 7, '$' . number_format($balance, 2), 0, 1, 'R'); return $pdf->Output('S'); } private function renderErrorPdf(string $message): string { - $pdf = new \FPDF; + $pdf = new \FPDF(); $pdf->AddPage(); $pdf->SetFont('Arial', 'B', 16); $pdf->Cell(0, 10, 'Error', 0, 1, 'C'); diff --git a/app/Services/Invoices/InvoiceService.php b/app/Services/Invoices/InvoiceService.php index 0d6b03c5..2325ab9d 100644 --- a/app/Services/Invoices/InvoiceService.php +++ b/app/Services/Invoices/InvoiceService.php @@ -13,7 +13,8 @@ class InvoiceService private InvoiceGenerationService $generation, private InvoiceTuitionService $tuition, private InvoiceGradeService $grades - ) {} + ) { + } public function getDefaultSchoolYear(): string { diff --git a/app/Services/Invoices/InvoiceTuitionService.php b/app/Services/Invoices/InvoiceTuitionService.php index b3df5523..967c579e 100644 --- a/app/Services/Invoices/InvoiceTuitionService.php +++ b/app/Services/Invoices/InvoiceTuitionService.php @@ -13,7 +13,8 @@ class InvoiceTuitionService private float $secondStudentFee, private float $youthFee, private string $timezone - ) {} + ) { + } public function calculateTuitionFee(array $registeredKids, array $withdrawnKids, ?string $refundDeadline): float { @@ -60,7 +61,7 @@ class InvoiceTuitionService private function isRefundAllowed(?string $refundDeadline): bool { - if (! $refundDeadline) { + if (!$refundDeadline) { return true; } @@ -68,7 +69,6 @@ class InvoiceTuitionService $tz = new \DateTimeZone($this->timezone); $today = new \DateTimeImmutable('today', $tz); $deadline = new \DateTimeImmutable($refundDeadline, $tz); - return $today <= $deadline; } catch (\Throwable $e) { return true; diff --git a/app/Services/Messaging/MessageCommandService.php b/app/Services/Messaging/MessageCommandService.php index 28ff9ab9..d4a8b54a 100644 --- a/app/Services/Messaging/MessageCommandService.php +++ b/app/Services/Messaging/MessageCommandService.php @@ -10,16 +10,18 @@ use RuntimeException; class MessageCommandService { - public function __construct(private GlobalConfigService $configService) {} + public function __construct(private GlobalConfigService $configService) + { + } public function create(int $senderId, array $payload, ?UploadedFile $attachment = null): Message { $recipientId = $payload['recipient_id'] ?? null; - if (! $recipientId && ! empty($payload['recipient_role'])) { + if (!$recipientId && !empty($payload['recipient_role'])) { $recipientId = $this->recipientIdFromRole($payload['recipient_role']); } - if (! $recipientId) { + if (!$recipientId) { throw new RuntimeException('Recipient is required.'); } @@ -40,7 +42,7 @@ class MessageCommandService 'message' => (string) $payload['message'], 'sent_datetime' => now(), 'read_status' => 0, - 'message_number' => 'MSG-'.now()->format('YmdHis'), + 'message_number' => 'MSG-' . now()->format('YmdHis'), 'priority' => $payload['priority'] ?? 'normal', 'attachment' => $path, 'status' => $payload['status'] ?? 'sent', @@ -48,7 +50,7 @@ class MessageCommandService 'school_year' => $payload['school_year'] ?? $this->configService->getSchoolYear() ?? '', ]); - if (! $message) { + if (!$message) { throw new RuntimeException('Failed to send message.'); } @@ -74,7 +76,7 @@ class MessageCommandService } } - if (! empty($updates)) { + if (!empty($updates)) { $message->fill($updates); $message->save(); } @@ -87,7 +89,6 @@ class MessageCommandService { return DB::transaction(function () use ($message) { $message->status = 'trashed'; - return (bool) $message->save(); }); } @@ -116,7 +117,7 @@ class MessageCommandService ]; $key = strtolower(trim($roleName)); - if (! isset($map[$key])) { + if (!isset($map[$key])) { throw new RuntimeException('Invalid recipient role.'); } diff --git a/app/Services/Messaging/MessageQueryService.php b/app/Services/Messaging/MessageQueryService.php index 37008828..ed90bfb0 100644 --- a/app/Services/Messaging/MessageQueryService.php +++ b/app/Services/Messaging/MessageQueryService.php @@ -11,12 +11,11 @@ class MessageQueryService public function getUserRoleName(int $userId): ?string { $user = User::query()->with('roles')->find($userId); - if (! $user) { + if (!$user) { return null; } $role = $user->roles->sortBy('id')->first(); - return $role ? (string) $role->name : null; } @@ -68,7 +67,7 @@ class MessageQueryService ->pluck('id') ->all(); - if (! empty($ids)) { + if (!empty($ids)) { Message::query() ->whereIn('id', $ids) ->update([ @@ -91,7 +90,7 @@ class MessageQueryService { $query = Message::query()->with(['sender', 'recipient']); - if (! empty($filters['priority'])) { + if (!empty($filters['priority'])) { $query->where('priority', $filters['priority']); } @@ -99,8 +98,8 @@ class MessageQueryService $query->where('read_status', (int) $filters['read_status']); } - if (! empty($filters['search'])) { - $term = '%'.$filters['search'].'%'; + if (!empty($filters['search'])) { + $term = '%' . $filters['search'] . '%'; $query->where(function ($q) use ($term) { $q->where('subject', 'like', $term) ->orWhere('message', 'like', $term); diff --git a/app/Services/Messaging/MessageRecipientService.php b/app/Services/Messaging/MessageRecipientService.php index 99fcc905..f75c6cdf 100644 --- a/app/Services/Messaging/MessageRecipientService.php +++ b/app/Services/Messaging/MessageRecipientService.php @@ -22,7 +22,7 @@ class MessageRecipientService return $rows ->map(fn ($row) => [ 'id' => (int) $row->teacher_id, - 'name' => trim($row->firstname.' '.$row->lastname), + 'name' => trim($row->firstname . ' ' . $row->lastname), ]) ->unique('id') ->values() @@ -81,7 +81,7 @@ class MessageRecipientService return $users ->map(fn ($row) => [ 'id' => (int) $row->id, - 'name' => trim($row->firstname.' '.$row->lastname), + 'name' => trim($row->firstname . ' ' . $row->lastname), ]) ->unique('id') ->values() diff --git a/app/Services/Navigation/NavBuilderService.php b/app/Services/Navigation/NavBuilderService.php index 4d8c18f8..93617a4d 100644 --- a/app/Services/Navigation/NavBuilderService.php +++ b/app/Services/Navigation/NavBuilderService.php @@ -6,10 +6,13 @@ use App\Models\NavItem; use App\Models\Role; use App\Models\RoleNavItem; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; class NavBuilderService { - public function __construct(private NavbarService $navbarService) {} + public function __construct(private NavbarService $navbarService) + { + } public function getAdminPayload(): array { @@ -74,7 +77,7 @@ class NavBuilderService $menuParentId = null; } - if ($menuParentId !== null && ! NavItem::query()->whereKey($menuParentId)->exists()) { + if ($menuParentId !== null && !NavItem::query()->whereKey($menuParentId)->exists()) { return ['ok' => false, 'message' => 'Selected parent does not exist.']; } @@ -85,7 +88,7 @@ class NavBuilderService 'icon_class' => trim((string) ($payload['icon_class'] ?? '')) ?: null, 'target' => trim((string) ($payload['target'] ?? '')) ?: null, 'sort_order' => (int) ($payload['sort_order'] ?? 0), - 'is_enabled' => ! empty($payload['is_enabled']) ? 1 : 0, + 'is_enabled' => !empty($payload['is_enabled']) ? 1 : 0, ]; $roleIds = array_values(array_unique(array_filter( @@ -187,7 +190,7 @@ class NavBuilderService } $roleId = (int) ($row['role_id'] ?? 0); - $roleName = $row['role_name'] ?? ($roleId ? ('#'.$roleId) : null); + $roleName = $row['role_name'] ?? ($roleId ? ('#' . $roleId) : null); if ($roleId > 0) { $roleAssignments[$navId]['ids'][] = $roleId; @@ -223,7 +226,7 @@ class NavBuilderService ], ]; - if (! empty($node['children'])) { + if (!empty($node['children'])) { $output = array_merge($output, $this->flattenTreeForResponse($node['children'], $roleAssignments, $depth + 1)); } } @@ -236,7 +239,6 @@ class NavBuilderService $s = trim(preg_replace('/\s+/', ' ', $s)); $s = preg_replace('/^[^[:alnum:]]+/u', '', $s); $s = preg_replace('/^(?i)(the|an|a)\s+/', '', $s); - return mb_strtolower($s, 'UTF-8'); } @@ -248,7 +250,7 @@ class NavBuilderService return $result !== 0 ? $result : ((int) ($a['id'] ?? 0) <=> (int) ($b['id'] ?? 0)); }); foreach ($nodes as &$node) { - if (! empty($node['children'])) { + if (!empty($node['children'])) { $this->sortTreeAlpha($node['children']); } } diff --git a/app/Services/Navigation/NavbarService.php b/app/Services/Navigation/NavbarService.php index 6936396a..cf9d6778 100644 --- a/app/Services/Navigation/NavbarService.php +++ b/app/Services/Navigation/NavbarService.php @@ -11,7 +11,7 @@ class NavbarService public function getMenuForRoles(array $roles): array { $roles = array_values(array_filter(array_map(fn ($r) => strtolower(trim((string) $r)), $roles))); - $cacheKey = 'navbar_'.md5(json_encode($roles)); + $cacheKey = 'navbar_' . md5(json_encode($roles)); return Cache::remember($cacheKey, 300, function () use ($roles) { $allowedIds = RoleNavItem::getNavItemIdsForRoles($roles); @@ -75,7 +75,7 @@ class NavbarService }); foreach ($nodes as &$node) { - if (! empty($node['children'])) { + if (!empty($node['children'])) { $this->sortTreeAlpha($node['children']); } } diff --git a/app/Services/Notifications/NotificationManagementService.php b/app/Services/Notifications/NotificationManagementService.php index 9bacc69d..d692725b 100644 --- a/app/Services/Notifications/NotificationManagementService.php +++ b/app/Services/Notifications/NotificationManagementService.php @@ -9,7 +9,7 @@ class NotificationManagementService public function update(int $notificationId, array $payload): array { $notification = Notification::query()->find($notificationId); - if (! $notification) { + if (!$notification) { return ['ok' => false, 'message' => 'Notification not found.']; } @@ -33,7 +33,7 @@ class NotificationManagementService public function delete(int $notificationId): bool { $notification = Notification::query()->find($notificationId); - if (! $notification) { + if (!$notification) { return false; } diff --git a/app/Services/Notifications/NotificationReadService.php b/app/Services/Notifications/NotificationReadService.php index 595ec09c..a8aef10a 100644 --- a/app/Services/Notifications/NotificationReadService.php +++ b/app/Services/Notifications/NotificationReadService.php @@ -13,7 +13,7 @@ class NotificationReadService ->where('notification_id', $notificationId) ->first(); - if (! $row) { + if (!$row) { return false; } diff --git a/app/Services/Notifications/NotificationRecipientService.php b/app/Services/Notifications/NotificationRecipientService.php index 9a06446b..a857e941 100644 --- a/app/Services/Notifications/NotificationRecipientService.php +++ b/app/Services/Notifications/NotificationRecipientService.php @@ -9,7 +9,6 @@ class NotificationRecipientService public function getRecipients(string $targetGroup): array { $rows = User::getUsersByRole($targetGroup); - return is_array($rows) ? $rows : []; } } diff --git a/app/Services/Notifications/NotificationSendService.php b/app/Services/Notifications/NotificationSendService.php index cc701c64..5fd6dc1d 100644 --- a/app/Services/Notifications/NotificationSendService.php +++ b/app/Services/Notifications/NotificationSendService.php @@ -12,7 +12,8 @@ class NotificationSendService public function __construct( private NotificationRecipientService $recipients, private NotificationDispatchService $dispatcher - ) {} + ) { + } public function send(array $payload, int $actorId): array { @@ -56,11 +57,11 @@ class NotificationSendService ]); $created++; - if (in_array('email', $channels, true) && ! empty($user['email'])) { + if (in_array('email', $channels, true) && !empty($user['email'])) { $this->dispatcher->sendEmail((string) $user['email'], (string) $payload['title'], (string) $payload['message']); } - if (in_array('sms', $channels, true) && ! empty($user['phone'])) { + if (in_array('sms', $channels, true) && !empty($user['phone'])) { $this->dispatcher->sendSms((string) $user['phone'], (string) $payload['message']); } } diff --git a/app/Services/Notifications/NotificationUserListService.php b/app/Services/Notifications/NotificationUserListService.php index 0c9d3f0b..65cdd23b 100644 --- a/app/Services/Notifications/NotificationUserListService.php +++ b/app/Services/Notifications/NotificationUserListService.php @@ -15,7 +15,7 @@ class NotificationUserListService $sortDir = strtolower((string) ($filters['sort_dir'] ?? 'desc')) === 'asc' ? 'asc' : 'desc'; $allowedSorts = ['created_at', 'scheduled_at', 'priority']; - if (! in_array($sortBy, $allowedSorts, true)) { + if (!in_array($sortBy, $allowedSorts, true)) { $sortBy = 'created_at'; } @@ -40,7 +40,7 @@ class NotificationUserListService } $paginator = $query - ->orderBy('notifications.'.$sortBy, $sortDir) + ->orderBy('notifications.' . $sortBy, $sortDir) ->paginate($perPage, ['*'], 'page', $page); return [ diff --git a/app/Services/Parents/AuthorizedUsersManagementService.php b/app/Services/Parents/AuthorizedUsersManagementService.php index 569a7d9e..e34a6a23 100644 --- a/app/Services/Parents/AuthorizedUsersManagementService.php +++ b/app/Services/Parents/AuthorizedUsersManagementService.php @@ -2,7 +2,6 @@ namespace App\Services\Parents; -use App\Controllers\View\AuthorizedUsersController; use App\Models\AuthorizedUser; use App\Models\User; use App\Services\ApplicationUrlService; @@ -10,7 +9,7 @@ use App\Services\Email\EmailDispatchService; use Illuminate\Support\Facades\DB; /** - * legacy {@see AuthorizedUsersController} parity. + * legacy {@see \App\Controllers\View\AuthorizedUsersController} parity. */ class AuthorizedUsersManagementService { diff --git a/app/Services/Parents/ParentAttendanceReportCalendarService.php b/app/Services/Parents/ParentAttendanceReportCalendarService.php index 7e5428fd..f7f03c12 100644 --- a/app/Services/Parents/ParentAttendanceReportCalendarService.php +++ b/app/Services/Parents/ParentAttendanceReportCalendarService.php @@ -6,7 +6,9 @@ use Illuminate\Support\Facades\DB; class ParentAttendanceReportCalendarService { - public function __construct(private ParentConfigService $configService) {} + public function __construct(private ParentConfigService $configService) + { + } /** * @return array{0: array, 1: string} @@ -31,7 +33,7 @@ class ParentAttendanceReportCalendarService $dates = []; for ($i = $weeksBefore; $i >= 1; $i--) { - $dates[] = $thisSunday->copy()->modify('-'.$i.' week'); + $dates[] = $thisSunday->copy()->modify('-' . $i . ' week'); } $cursor = $thisSunday->copy(); @@ -70,13 +72,13 @@ class ParentAttendanceReportCalendarService $filtered = []; foreach ($dates as $d) { $ymd = $d->format('Y-m-d'); - if (! isset($noSchool[$ymd]) && $d >= $today && $d <= $cap) { + if (!isset($noSchool[$ymd]) && $d >= $today && $d <= $cap) { $filtered[] = $d; } } $defaultYmd = $default->format('Y-m-d'); - if (! empty($filtered)) { + if (!empty($filtered)) { $defaultYmd = $filtered[0]->format('Y-m-d'); } @@ -99,10 +101,8 @@ class ParentAttendanceReportCalendarService } if (preg_match('/^(\\d{1,2}):(\\d{2})$/', $raw, $m)) { $hh = str_pad((string) ((int) $m[1]), 2, '0', STR_PAD_LEFT); - - return $hh.':'.$m[2]; + return $hh . ':' . $m[2]; } - return $default; } diff --git a/app/Services/Parents/ParentAttendanceReportService.php b/app/Services/Parents/ParentAttendanceReportService.php index 99a70ddc..19a6812e 100644 --- a/app/Services/Parents/ParentAttendanceReportService.php +++ b/app/Services/Parents/ParentAttendanceReportService.php @@ -2,14 +2,12 @@ namespace App\Services\Parents; -use App\Controllers\View\ParentAttendanceReportController; -use App\Http\Controllers\Api\Reports\FilesController; use App\Models\AttendanceData; use App\Models\AttendanceRecord; -use App\Models\ClassSection; use App\Models\EarlyDismissalSignature; use App\Models\ParentAttendanceReport; use App\Models\Student; +use App\Models\ClassSection; use App\Services\SemesterRangeService; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\DB; @@ -20,7 +18,8 @@ class ParentAttendanceReportService private ParentConfigService $configService, private ParentAttendanceReportCalendarService $calendarService, private SemesterRangeService $semesterRangeService - ) {} + ) { + } public function formData(int $parentId): array { @@ -91,7 +90,7 @@ class ParentAttendanceReportService } $type = (string) ($payload['type'] ?? ''); - if (! in_array($type, ['absent', 'late', 'early_dismissal'], true)) { + if (!in_array($type, ['absent', 'late', 'early_dismissal'], true)) { throw new \RuntimeException('Invalid report type.'); } @@ -105,8 +104,8 @@ class ParentAttendanceReportService foreach ($rawDates as $entry) { $dt = \DateTime::createFromFormat('Y-m-d', $entry); - if (! $dt) { - throw new \RuntimeException('Invalid date selected: '.$entry); + if (!$dt) { + throw new \RuntimeException('Invalid date selected: ' . $entry); } if ((int) $dt->format('w') !== 0) { throw new \RuntimeException('Please select Sunday dates only.'); @@ -120,10 +119,10 @@ class ParentAttendanceReportService $validDates[$entry] = $dt; } - if ($type === 'late' && (! is_string($arrivalTime) || $arrivalTime === '')) { + if ($type === 'late' && (!is_string($arrivalTime) || $arrivalTime === '')) { throw new \RuntimeException('Please provide an expected arrival time for late reporting.'); } - if ($type === 'early_dismissal' && (! is_string($dismissTime) || $dismissTime === '')) { + if ($type === 'early_dismissal' && (!is_string($dismissTime) || $dismissTime === '')) { throw new \RuntimeException('Please provide a dismissal time for early dismissal.'); } if ($type !== 'early_dismissal') { @@ -148,7 +147,7 @@ class ParentAttendanceReportService ->first(); $classSectionId = $sectionRow->class_section_id ?? null; $student = Student::query()->select('firstname', 'lastname')->find($sid); - $studentName = $student ? trim($student->firstname.' '.$student->lastname) : ('Student #'.$sid); + $studentName = $student ? trim($student->firstname . ' ' . $student->lastname) : ('Student #' . $sid); $classLabel = $this->resolveClassSectionLabel($classSectionId); foreach ($validDates as $reportDate => $_dt) { @@ -164,7 +163,7 @@ class ParentAttendanceReportService ->whereIn('type', ['absent', 'late']) ->first(); if ($existingAL) { - $blocked[] = $studentName.' ('.$reportDate.')'; + $blocked[] = $studentName . ' (' . $reportDate . ')'; } else { $existingED = (clone $qb)->where('type', 'early_dismissal')->first(); if ($existingED) { @@ -196,7 +195,7 @@ class ParentAttendanceReportService ->whereIn('type', ['absent', 'late', 'early_dismissal']) ->first(); if ($existingAny) { - $blocked[] = $studentName.' ('.$reportDate.')'; + $blocked[] = $studentName . ' (' . $reportDate . ')'; } else { ParentAttendanceReport::query()->create([ 'parent_id' => $parentId, @@ -243,8 +242,8 @@ class ParentAttendanceReportService } if ($inserted <= 0) { - $err = ! empty($blocked) - ? ('Already submitted and cannot be changed for: '.implode(', ', array_slice($blocked, 0, 5)).(count($blocked) > 5 ? '…' : '')) + $err = !empty($blocked) + ? ('Already submitted and cannot be changed for: ' . implode(', ', array_slice($blocked, 0, 5)) . (count($blocked) > 5 ? '…' : '')) : 'Could not save your report. Please try again.'; throw new \RuntimeException($err); } @@ -279,7 +278,7 @@ class ParentAttendanceReportService }))); $type = (string) ($payload['type'] ?? ''); - if (empty($dateValues) || ! in_array($type, ['absent', 'late', 'early_dismissal'], true)) { + if (empty($dateValues) || !in_array($type, ['absent', 'late', 'early_dismissal'], true)) { throw new \RuntimeException('Invalid date or type.'); } @@ -313,7 +312,7 @@ class ParentAttendanceReportService if ($sid <= 0) { continue; } - if (! isset($map[$sid])) { + if (!isset($map[$sid])) { $map[$sid] = [ 'student_id' => $sid, 'firstname' => (string) ($row['firstname'] ?? ''), @@ -327,7 +326,7 @@ class ParentAttendanceReportService } $map[$sid]['dates'][$dVal] = $map[$sid]['dates'][$dVal] ?? []; $t = (string) ($row['type'] ?? ''); - if ($t !== '' && ! in_array($t, $map[$sid]['dates'][$dVal], true)) { + if ($t !== '' && !in_array($t, $map[$sid]['dates'][$dVal], true)) { $map[$sid]['dates'][$dVal][] = $t; } } @@ -338,7 +337,7 @@ class ParentAttendanceReportService public function updateReport(int $parentId, int $reportId, array $payload): void { $row = ParentAttendanceReport::query()->find($reportId); - if (! $row || (int) $row->parent_id !== $parentId) { + if (!$row || (int) $row->parent_id !== $parentId) { throw new \RuntimeException('Report not found.'); } @@ -348,7 +347,7 @@ class ParentAttendanceReportService $tzName = (string) (config('School')->attendance['timezone'] ?? 'UTC'); $tz = new \DateTimeZone($tzName ?: 'UTC'); - $cutoff = new \DateTime($row->report_date.' 09:00:00', $tz); + $cutoff = new \DateTime($row->report_date . ' 09:00:00', $tz); $now = new \DateTime('now', $tz); if ($now >= $cutoff) { throw new \RuntimeException('Editing window closed at 9:00 AM on the report date.'); @@ -364,13 +363,13 @@ class ParentAttendanceReportService ]; if ($type === 'late' && $arrival !== '') { - if (! preg_match('/^\\d{2}:\\d{2}(:\\d{2})?$/', $arrival)) { + if (!preg_match('/^\\d{2}:\\d{2}(:\\d{2})?$/', $arrival)) { throw new \RuntimeException('Invalid arrival time format.'); } $update['arrival_time'] = $arrival; } if ($type === 'early_dismissal' && $dismiss !== '') { - if (! preg_match('/^\\d{2}:\\d{2}(:\\d{2})?$/', $dismiss)) { + if (!preg_match('/^\\d{2}:\\d{2}(:\\d{2})?$/', $dismiss)) { throw new \RuntimeException('Invalid dismissal time format.'); } $update['dismiss_time'] = $dismiss; @@ -386,7 +385,7 @@ class ParentAttendanceReportService /** * Staff index: early dismissal rows grouped by date (+ signature metadata per date). * - * Parity with legacy {@see ParentAttendanceReportController::earlyDismissals}. + * Parity with legacy {@see \App\Controllers\View\ParentAttendanceReportController::earlyDismissals}. * * @return array{groups: array>>, school_year: string, semester: string, signature_by_date: array>} */ @@ -468,7 +467,7 @@ class ParentAttendanceReportService } /** - * Parity with legacy {@see ParentAttendanceReportController::addEarlyDismissalForm}. + * Parity with legacy {@see \App\Controllers\View\ParentAttendanceReportController::addEarlyDismissalForm}. * * @return array{students: array>, default_date: string, school_year: string, semester: string} */ @@ -506,7 +505,7 @@ class ParentAttendanceReportService } /** - * Parity with legacy {@see ParentAttendanceReportController::saveEarlyDismissal}. + * Parity with legacy {@see \App\Controllers\View\ParentAttendanceReportController::saveEarlyDismissal}. */ public function saveStaffEarlyDismissal(int $studentId, string $reportDate, string $dismissTime, string $reason): void { @@ -574,8 +573,8 @@ class ParentAttendanceReportService } /** - * Parity with legacy {@see ParentAttendanceReportController::uploadEarlyDismissalSignature}. - * Files live under {@see storage_path('uploads/early_dismissal_signatures')} (same as {@see FilesController::earlyDismissalSignature}). + * Parity with legacy {@see \App\Controllers\View\ParentAttendanceReportController::uploadEarlyDismissalSignature}. + * Files live under {@see storage_path('uploads/early_dismissal_signatures')} (same as {@see \App\Http\Controllers\Api\Reports\FilesController::earlyDismissalSignature}). */ public function storeEarlyDismissalSignature( UploadedFile $file, @@ -645,7 +644,7 @@ class ParentAttendanceReportService $oldFile = (string) ($existing->filename ?? ''); $existing->update($payload); if ($oldFile !== '' && $oldFile !== $filename) { - @unlink($targetDir.DIRECTORY_SEPARATOR.$oldFile); + @unlink($targetDir . DIRECTORY_SEPARATOR . $oldFile); } } else { EarlyDismissalSignature::query()->create($payload); @@ -681,7 +680,7 @@ class ParentAttendanceReportService return; } - if (! $classSectionId) { + if (!$classSectionId) { $row = DB::table('student_class') ->select('class_section_id') ->where('student_id', $studentId) @@ -704,19 +703,19 @@ class ParentAttendanceReportService $reasonParts = ['Parent-reported']; if ($type === 'late' && $arrivalTime) { - $reasonParts[] = 'ETA '.substr($arrivalTime, 0, 5); + $reasonParts[] = 'ETA ' . substr($arrivalTime, 0, 5); } - if (! empty($reason)) { + if (!empty($reason)) { $reasonParts[] = trim($reason); } $reasonText = implode(' — ', $reasonParts); - if (! $existing) { + if (!$existing) { $classId = ClassSection::query() ->where('class_section_id', $classSectionId) ->value('class_id'); $schoolId = Student::query()->whereKey($studentId)->value('school_id'); - if (! $classId || ! $schoolId) { + if (!$classId || !$schoolId) { return; } AttendanceData::query()->create([ @@ -731,7 +730,6 @@ class ParentAttendanceReportService 'school_year' => $schoolYear, ]); $this->bumpAttendanceRecord($studentId, $classSectionId, $schoolId, $status, $semester, $schoolYear); - return; } @@ -773,7 +771,6 @@ class ParentAttendanceReportService $updates['total_late']++; } $record->update($updates); - return; } diff --git a/app/Services/Parents/ParentAttendanceService.php b/app/Services/Parents/ParentAttendanceService.php index 09cf93f5..9bf02154 100644 --- a/app/Services/Parents/ParentAttendanceService.php +++ b/app/Services/Parents/ParentAttendanceService.php @@ -6,7 +6,9 @@ use Illuminate\Support\Facades\DB; class ParentAttendanceService { - public function __construct(private ParentConfigService $configService) {} + public function __construct(private ParentConfigService $configService) + { + } public function listAttendance(int $parentId, ?string $schoolYear = null): array { diff --git a/app/Services/Parents/ParentEmergencyContactService.php b/app/Services/Parents/ParentEmergencyContactService.php index 1baa6ab1..c42d29b5 100644 --- a/app/Services/Parents/ParentEmergencyContactService.php +++ b/app/Services/Parents/ParentEmergencyContactService.php @@ -10,7 +10,8 @@ class ParentEmergencyContactService public function __construct( private ParentConfigService $configService, private PhoneFormatterService $phoneFormatter - ) {} + ) { + } public function list(int $parentId): array { diff --git a/app/Services/Parents/ParentEnrollmentService.php b/app/Services/Parents/ParentEnrollmentService.php index b08fa238..7b5021ac 100644 --- a/app/Services/Parents/ParentEnrollmentService.php +++ b/app/Services/Parents/ParentEnrollmentService.php @@ -10,7 +10,9 @@ use Illuminate\Support\Facades\DB; class ParentEnrollmentService { - public function __construct(private ParentConfigService $configService) {} + public function __construct(private ParentConfigService $configService) + { + } public function overview(int $parentId, ?string $schoolYear = null): array { @@ -24,11 +26,11 @@ class ParentEnrollmentService ->get() ->map(function ($student) use ($selectedYear) { $classSections = StudentClass::getClassSectionsByStudentId($student->id, $selectedYear, true); - $student->class_section = ! empty($classSections) + $student->class_section = !empty($classSections) ? implode(', ', $classSections) : 'Class not Assigned'; - $isArabicClass = ! empty($classSections) && array_reduce( + $isArabicClass = !empty($classSections) && array_reduce( $classSections, static fn ($carry, $name) => $carry || (is_string($name) && stripos($name, 'arabic') === 0), false @@ -179,7 +181,7 @@ class ParentEnrollmentService ->where('is_withdrawn', 0) ->first(); - if (! $enrollment) { + if (!$enrollment) { continue; } @@ -204,7 +206,7 @@ class ParentEnrollmentService if ($refund) { $refund->update([ - 'reason' => 'Withdrawal under review for student ID '.$studentId, + 'reason' => 'Withdrawal under review for student ID ' . $studentId, 'note' => null, 'updated_by' => $parentId, ]); @@ -215,7 +217,7 @@ class ParentEnrollmentService 'requested_at' => now(), 'school_year' => $schoolYear, 'status' => Refund::STATUS_PENDING, - 'reason' => 'Withdrawal under review for student ID '.$studentId, + 'reason' => 'Withdrawal under review for student ID ' . $studentId, 'request' => 'new', 'semester' => $semester, 'refund_paid_amount' => 0.0, diff --git a/app/Services/Parents/ParentEventParticipationService.php b/app/Services/Parents/ParentEventParticipationService.php index 7298cd05..e1bb7b57 100644 --- a/app/Services/Parents/ParentEventParticipationService.php +++ b/app/Services/Parents/ParentEventParticipationService.php @@ -2,9 +2,9 @@ namespace App\Services\Parents; -use App\Models\Enrollment; use App\Models\Event; use App\Models\EventCharges; +use App\Models\Enrollment; use App\Models\Student; use App\Services\Invoices\InvoiceGenerationService; @@ -13,7 +13,8 @@ class ParentEventParticipationService public function __construct( private ParentConfigService $configService, private InvoiceGenerationService $invoiceGeneration - ) {} + ) { + } public function overview(int $parentId): array { @@ -26,7 +27,7 @@ class ParentEventParticipationService $charges = []; foreach ($chargesList as $charge) { - $key = $charge['student_id'].':'.$charge['event_id']; + $key = $charge['student_id'] . ':' . $charge['event_id']; $charges[$key] = [ 'participation' => $charge['participation'], 'date' => $charge['updated_at'] ?? $charge['created_at'], @@ -106,7 +107,6 @@ class ParentEventParticipationService if ($existing) { $existing->delete(); } - continue; } diff --git a/app/Services/Parents/ParentProfileService.php b/app/Services/Parents/ParentProfileService.php index 1ce98558..a04e231f 100644 --- a/app/Services/Parents/ParentProfileService.php +++ b/app/Services/Parents/ParentProfileService.php @@ -9,7 +9,6 @@ class ParentProfileService public function getProfile(int $parentId): ?array { $user = User::query()->find($parentId); - return $user ? $user->toArray() : null; } diff --git a/app/Services/Parents/ParentProgressQueryService.php b/app/Services/Parents/ParentProgressQueryService.php index 8773cc86..2dcbfa7b 100644 --- a/app/Services/Parents/ParentProgressQueryService.php +++ b/app/Services/Parents/ParentProgressQueryService.php @@ -2,16 +2,13 @@ namespace App\Services\Parents; -use App\Controllers\ParentProgressController; -use App\Http\Resources\ClassProgress\ClassProgressReportResource; use App\Models\ClassProgressReport; use App\Services\ClassProgress\ClassProgressQueryService; -use Carbon\CarbonInterface; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; /** - * legacy {@see ParentProgressController} read-side logic. + * legacy {@see \App\Controllers\ParentProgressController} read-side logic. */ class ParentProgressQueryService { @@ -136,7 +133,7 @@ class ParentProgressQueryService $statusLabel = $statusOptions[$row->status] ?? 'Unknown'; $row->setAttribute('status_label', $statusLabel); - $weekStart = $row->week_start instanceof CarbonInterface + $weekStart = $row->week_start instanceof \Carbon\CarbonInterface ? $row->week_start->format('Y-m-d') : (string) $row->week_start; $sectionId = (int) $row->class_section_id; @@ -148,7 +145,7 @@ class ParentProgressQueryService if (! isset($reportGroups[$key])) { $reportGroups[$key] = [ 'week_start' => $weekStart, - 'week_end' => $row->week_end instanceof CarbonInterface + 'week_end' => $row->week_end instanceof \Carbon\CarbonInterface ? $row->week_end->format('Y-m-d') : (string) ($row->week_end ?? ''), 'class_section_name' => $row->class_section_name ?? '', @@ -162,7 +159,7 @@ class ParentProgressQueryService continue; } - $reportGroups[$key]['reports'][$subject] = (new ClassProgressReportResource($row))->toArray(request()); + $reportGroups[$key]['reports'][$subject] = (new \App\Http\Resources\ClassProgress\ClassProgressReportResource($row))->toArray(request()); } return $reportGroups; diff --git a/app/Services/Parents/ParentRegistrationService.php b/app/Services/Parents/ParentRegistrationService.php index a675a49f..ba0a7a7f 100644 --- a/app/Services/Parents/ParentRegistrationService.php +++ b/app/Services/Parents/ParentRegistrationService.php @@ -15,7 +15,8 @@ class ParentRegistrationService public function __construct( private ParentConfigService $configService, private SchoolIdService $schoolIdService - ) {} + ) { + } public function overview(int $parentId): array { @@ -38,7 +39,6 @@ class ParentRegistrationService $kids = $kids->map(function ($kid) use ($allergies, $conditions) { $kid->allergies = ($allergies[$kid->id] ?? collect())->pluck('allergy')->all(); $kid->medical_conditions = ($conditions[$kid->id] ?? collect())->pluck('condition_name')->all(); - return $kid->toArray(); })->all(); @@ -105,7 +105,6 @@ class ParentRegistrationService 'dob' => $student['dob'], 'reason' => 'already_registered', ]; - continue; } @@ -116,7 +115,7 @@ class ParentRegistrationService 'age' => $this->calculateAge($student['dob'], $ageReference), 'gender' => $student['gender'], 'registration_grade' => $student['registration_grade'] ?? null, - 'photo_consent' => ! empty($student['photo_consent']) ? 1 : 0, + 'photo_consent' => !empty($student['photo_consent']) ? 1 : 0, 'parent_id' => $parentId, 'year_of_registration' => (string) date('Y'), 'school_year' => $schoolYear, @@ -187,7 +186,7 @@ class ParentRegistrationService 'age' => $this->calculateAge($payload['dob'], $ageReference), 'gender' => $payload['gender'], 'registration_grade' => $payload['registration_grade'] ?? null, - 'photo_consent' => ! empty($payload['photo_consent']) ? 1 : 0, + 'photo_consent' => !empty($payload['photo_consent']) ? 1 : 0, ]); StudentMedicalCondition::query()->where('student_id', $studentId)->delete(); @@ -235,7 +234,6 @@ class ParentRegistrationService try { $dobObj = new \DateTimeImmutable($dob); $refObj = new \DateTimeImmutable($referenceDate); - return (int) $dobObj->diff($refObj)->y; } catch (\Throwable $e) { return 0; diff --git a/app/Services/Parents/ParentReportCardService.php b/app/Services/Parents/ParentReportCardService.php index 0972e662..e1ab3167 100644 --- a/app/Services/Parents/ParentReportCardService.php +++ b/app/Services/Parents/ParentReportCardService.php @@ -2,15 +2,14 @@ namespace App\Services\Parents; -use App\Controllers\ParentReportCardController; use App\Models\Configuration; +use App\Services\ApplicationUrlService; use App\Models\ReportCardAcknowledgement; use App\Models\User; -use App\Services\ApplicationUrlService; use Illuminate\Support\Facades\DB; /** - * legacy {@see ParentReportCardController} parity (read + acknowledgement). + * legacy {@see \App\Controllers\ParentReportCardController} parity (read + acknowledgement). */ class ParentReportCardService { @@ -86,7 +85,7 @@ class ParentReportCardService } /** - * @param list $studentIds + * @param list $studentIds * @return array> */ public function acknowledgementMap(int $primaryParentUserId, array $studentIds, string $schoolYear, string $semester): array @@ -118,7 +117,7 @@ class ParentReportCardService } /** - * @param array $values viewed_at, signed_at, signed_name, signer_ip, … + * @param array $values viewed_at, signed_at, signed_name, signer_ip, … */ public function touchAcknowledgement( int $primaryParentUserId, diff --git a/app/Services/Parents/PrimaryParentUserResolver.php b/app/Services/Parents/PrimaryParentUserResolver.php index ade3ba7c..42cf1b8d 100644 --- a/app/Services/Parents/PrimaryParentUserResolver.php +++ b/app/Services/Parents/PrimaryParentUserResolver.php @@ -2,15 +2,13 @@ namespace App\Services\Parents; -use App\Controllers\ParentReportCardController; -use App\Models\Student; use App\Models\User; use Illuminate\Support\Facades\DB; /** * Maps the logged-in parent-family account to the primary parent's user id - * (stored on {@see Student::$parent_id}), matching legacy - * {@see ParentReportCardController::resolvePrimaryParentId}. + * (stored on {@see \App\Models\Student::$parent_id}), matching legacy + * {@see \App\Controllers\ParentReportCardController::resolvePrimaryParentId}. */ final class PrimaryParentUserResolver { @@ -24,7 +22,7 @@ final class PrimaryParentUserResolver } /** - * @param int $userId Session user id (may be secondary/tertiary login). + * @param int $userId Session user id (may be secondary/tertiary login). */ public function resolveFromCredentials(int $userId, string $userType): ?int { diff --git a/app/Services/Payments/PaymentEnrollmentEventService.php b/app/Services/Payments/PaymentEnrollmentEventService.php index 8881e570..ad162049 100644 --- a/app/Services/Payments/PaymentEnrollmentEventService.php +++ b/app/Services/Payments/PaymentEnrollmentEventService.php @@ -10,7 +10,8 @@ class PaymentEnrollmentEventService { public function __construct( private ApplicationUrlService $urls, - ) {} + ) { + } public function buildEventData( int $parentId, @@ -28,7 +29,7 @@ class PaymentEnrollmentEventService ->where('id', $parentId) ->first(); - if (! $parent) { + if (!$parent) { throw new \RuntimeException("Parent user #{$parentId} not found"); } @@ -103,7 +104,7 @@ class PaymentEnrollmentEventService } $seen[$sid] = true; - $teacherFull = trim(trim((string) ($row['t_firstname'] ?? '')).' '.trim((string) ($row['t_lastname'] ?? ''))); + $teacherFull = trim(trim((string) ($row['t_firstname'] ?? '')) . ' ' . trim((string) ($row['t_lastname'] ?? ''))); $teacherFull = $teacherFull !== '' ? $teacherFull : null; $students[] = [ @@ -111,7 +112,7 @@ class PaymentEnrollmentEventService 'student_id' => $sid, 'firstname' => (string) ($row['s_firstname'] ?? ''), 'lastname' => (string) ($row['s_lastname'] ?? ''), - 'name' => trim(((string) ($row['s_firstname'] ?? '')).' '.((string) ($row['s_lastname'] ?? ''))), + 'name' => trim(((string) ($row['s_firstname'] ?? '')) . ' ' . ((string) ($row['s_lastname'] ?? ''))), 'registration_grade' => (string) ($row['registration_grade'] ?? ''), 'class_section_id' => isset($row['class_section_id']) ? (int) $row['class_section_id'] : null, 'class_section_name' => $row['class_section_name'] ?? null, diff --git a/app/Services/Payments/PaymentEventChargesService.php b/app/Services/Payments/PaymentEventChargesService.php index 2fd3b49e..838da34a 100644 --- a/app/Services/Payments/PaymentEventChargesService.php +++ b/app/Services/Payments/PaymentEventChargesService.php @@ -11,7 +11,9 @@ use Illuminate\Support\Facades\DB; class PaymentEventChargesService { - public function __construct(private ChargeService $chargeService) {} + public function __construct(private ChargeService $chargeService) + { + } public function listCharges(?string $schoolYear, ?string $semester): array { @@ -54,7 +56,7 @@ class PaymentEventChargesService $count = 0; - if (! empty($studentIds)) { + if (!empty($studentIds)) { foreach ($studentIds as $studentId) { $result = $this->chargeService->createEventCharge([ 'parent_id' => $parentId, @@ -71,7 +73,7 @@ class PaymentEventChargesService $count++; } } - } elseif (! empty($payload['student_id'])) { + } elseif (!empty($payload['student_id'])) { $result = $this->chargeService->createEventCharge([ 'parent_id' => $parentId, 'student_id' => (int) $payload['student_id'], diff --git a/app/Services/Payments/PaymentManualService.php b/app/Services/Payments/PaymentManualService.php index 0a975af3..72c6788b 100644 --- a/app/Services/Payments/PaymentManualService.php +++ b/app/Services/Payments/PaymentManualService.php @@ -17,7 +17,8 @@ class PaymentManualService public function __construct( private DiscountInvoiceService $invoiceService, private PaymentEnrollmentEventService $enrollmentEventService - ) {} + ) { + } public function search(string $searchTerm, ?string $schoolYear = null): array { @@ -47,9 +48,9 @@ class PaymentManualService $builder->where(function ($q) use ($searchTerm, $searchClean, $searchFormatted) { $q->where('email', $searchTerm); - if (! empty($searchClean)) { + if (!empty($searchClean)) { if (strlen($searchClean) === 10) { - $formattedPhone = substr($searchClean, 0, 3).'-'.substr($searchClean, 3, 3).'-'.substr($searchClean, 6, 4); + $formattedPhone = substr($searchClean, 0, 3) . '-' . substr($searchClean, 3, 3) . '-' . substr($searchClean, 6, 4); $q->orWhere('cellphone', $formattedPhone); } @@ -59,13 +60,13 @@ class PaymentManualService ); } - if (! empty($searchFormatted)) { + if (!empty($searchFormatted)) { $q->orWhere('cellphone', $searchFormatted); } }); $parent = (array) $builder->first(); - if (! empty($parent)) { + if (!empty($parent)) { unset($parent['password']); $parentData = $parent; $parentId = (int) ($parent['id'] ?? 0); @@ -126,23 +127,23 @@ class PaymentManualService OR email LIKE ? OR cellphone LIKE ?"; - $params = ['%'.$q.'%', '%'.$q.'%', '%'.$q.'%']; + $params = ['%' . $q . '%', '%' . $q . '%', '%' . $q . '%']; if ($digits !== '') { $sql .= " OR REPLACE(REPLACE(REPLACE(REPLACE(cellphone, '(', ''), ')', ''), '-', ''), ' ', '') LIKE ?"; - $params[] = '%'.$digits.'%'; + $params[] = '%' . $digits . '%'; } - $sql .= ') ORDER BY lastname, firstname LIMIT 20'; + $sql .= ") ORDER BY lastname, firstname LIMIT 20"; $rows = DB::select($sql, $params); $items = []; foreach ($rows as $row) { - $label = trim(($row->firstname ?? '').' '.($row->lastname ?? '')); + $label = trim(($row->firstname ?? '') . ' ' . ($row->lastname ?? '')); $email = trim((string) ($row->email ?? '')); $phone = trim((string) ($row->cellphone ?? '')); - $sub = trim($email.' '.$phone); + $sub = trim($email . ' ' . $phone); $value = $email !== '' ? $email : ($phone !== '' ? $phone : $label); $items[] = [ @@ -171,7 +172,7 @@ class PaymentManualService $paymentMethod = strtolower(trim($paymentMethod)); $allowedMethods = ['cash', 'check', 'card']; - if (! in_array($paymentMethod, $allowedMethods, true)) { + if (!in_array($paymentMethod, $allowedMethods, true)) { throw new \InvalidArgumentException('Invalid payment method.'); } @@ -184,7 +185,7 @@ class PaymentManualService } $invoice = Invoice::query()->find($invoiceId); - if (! $invoice) { + if (!$invoice) { throw new \RuntimeException('Invoice not found.'); } @@ -208,7 +209,7 @@ class PaymentManualService try { $locked = DB::table('invoices')->where('id', $invoiceId)->lockForUpdate()->first(); - if (! $locked) { + if (!$locked) { DB::rollBack(); throw new \RuntimeException('Invoice not found.'); } @@ -229,7 +230,7 @@ class PaymentManualService $paidCount = $this->getSuccessfulPaymentCount($invoiceId); $installmentSeq = $paidCount + 1; - $transactionId = 'INV-'.$invoiceId.'-'.str_replace('.', '', (string) microtime(true)); + $transactionId = 'INV-' . $invoiceId . '-' . str_replace('.', '', (string) microtime(true)); $ok = $this->processPayment( $invoiceId, @@ -245,7 +246,7 @@ class PaymentManualService $userId ); - if (! $ok) { + if (!$ok) { DB::rollBack(); throw new \RuntimeException('Failed to record payment.'); } @@ -307,7 +308,7 @@ class PaymentManualService ]; } catch (\Throwable $e) { DB::rollBack(); - Log::error('[manualPayUpdate] '.$e->getMessage()); + Log::error('[manualPayUpdate] ' . $e->getMessage()); throw $e; } } @@ -327,12 +328,12 @@ class PaymentManualService } $payment = Payment::query()->find($paymentId); - if (! $payment) { + if (!$payment) { throw new \RuntimeException('Original payment not found.'); } $invoice = Invoice::query()->find((int) $payment->invoice_id); - if (! $invoice) { + if (!$invoice) { throw new \RuntimeException('Linked invoice not found.'); } @@ -366,10 +367,10 @@ class PaymentManualService { $filename = basename($filename); $roots = [ - storage_path('app/uploads/checks/'.$filename), - storage_path('app/uploads/cards/'.$filename), - storage_path('app/uploads/misc/'.$filename), - storage_path('app/uploads/'.$filename), + storage_path('app/uploads/checks/' . $filename), + storage_path('app/uploads/cards/' . $filename), + storage_path('app/uploads/misc/' . $filename), + storage_path('app/uploads/' . $filename), ]; $path = null; @@ -380,14 +381,14 @@ class PaymentManualService } } - if (! $path) { + if (!$path) { abort(404, 'Payment file not found.'); } if ($mode === 'inline') { return response()->file($path, [ 'Content-Type' => mime_content_type($path) ?: 'application/octet-stream', - 'Content-Disposition' => 'inline; filename="'.$filename.'"', + 'Content-Disposition' => 'inline; filename="' . $filename . '"', ]); } @@ -408,7 +409,7 @@ class PaymentManualService ?int $userId ): bool { $invoice = Invoice::query()->find($invoiceId); - if (! $invoice) { + if (!$invoice) { return false; } @@ -432,7 +433,7 @@ class PaymentManualService 'updated_by' => $userId, ]; - if (! Invoice::query()->whereKey($invoiceId)->update($invoiceUpdateData)) { + if (!Invoice::query()->whereKey($invoiceId)->update($invoiceUpdateData)) { return false; } @@ -465,7 +466,7 @@ class PaymentManualService private function getCurrentInvoiceBalanceExcludingPayment(int $invoiceId, int $excludePaymentId): float { $invoice = Invoice::query()->find($invoiceId); - if (! $invoice) { + if (!$invoice) { return 0.0; } @@ -529,7 +530,7 @@ class PaymentManualService $discountByInvoice = []; $refundByInvoice = []; - if (! empty($invoiceIds)) { + if (!empty($invoiceIds)) { $rows = Payment::query() ->selectRaw('invoice_id, COALESCE(SUM(paid_amount),0) AS total_paid') ->whereIn('invoice_id', $invoiceIds) @@ -580,7 +581,7 @@ class PaymentManualService $issueYmd = ''; foreach (['issue_date', 'start_date', 'created_at'] as $k) { - if (! empty($inv[$k])) { + if (!empty($inv[$k])) { $its = strtotime((string) $inv[$k]); if ($its !== false) { $issueYmd = date('Y-m-d', $its); @@ -612,7 +613,7 @@ class PaymentManualService $okTypes = ['image/jpeg', 'image/png', 'application/pdf']; $okExts = ['jpg', 'jpeg', 'png', 'pdf']; - if (! in_array($mime, $okTypes, true) || ! in_array($ext, $okExts, true)) { + if (!in_array($mime, $okTypes, true) || !in_array($ext, $okExts, true)) { throw new \InvalidArgumentException('Unsupported file type. Use JPG, PNG, or PDF.'); } @@ -622,9 +623,9 @@ class PaymentManualService $fileName = $file->hashName(); $subdir = $paymentMethod === 'check' ? 'checks' : ($paymentMethod === 'card' ? 'cards' : 'misc'); - $targetDir = storage_path('app/uploads/'.$subdir); + $targetDir = storage_path('app/uploads/' . $subdir); - if (! is_dir($targetDir)) { + if (!is_dir($targetDir)) { mkdir($targetDir, 0775, true); } @@ -640,7 +641,7 @@ class PaymentManualService event($name, $payload); } } catch (\Throwable $e) { - Log::warning($name.' hook failed: '.$e->getMessage()); + Log::warning($name . ' hook failed: ' . $e->getMessage()); } } } diff --git a/app/Services/Payments/PaymentMissedCheckService.php b/app/Services/Payments/PaymentMissedCheckService.php index fc9fa0a6..1ae3e5b7 100644 --- a/app/Services/Payments/PaymentMissedCheckService.php +++ b/app/Services/Payments/PaymentMissedCheckService.php @@ -11,7 +11,8 @@ class PaymentMissedCheckService public function __construct( private UserNotificationDispatchService $notifier, private EmailService $emailService - ) {} + ) { + } public function findUsersWithMissedPayments(): array { @@ -45,7 +46,7 @@ class PaymentMissedCheckService foreach ($users as $user) { $userId = (int) ($user['user_id'] ?? 0); $email = (string) ($user['email'] ?? ''); - $name = trim((string) ($user['firstname'] ?? '').' '.(string) ($user['lastname'] ?? '')); + $name = trim((string) ($user['firstname'] ?? '') . ' ' . (string) ($user['lastname'] ?? '')); $this->notifier->notifyUser( $userId, @@ -58,8 +59,8 @@ class PaymentMissedCheckService if ($email !== '') { $subject = 'Payment Missed'; - $body = '

Dear '.e($name !== '' ? $name : 'Parent').',

' - .'

You have a missed payment. Please pay to avoid penalty.

'; + $body = '

Dear ' . e($name !== '' ? $name : 'Parent') . ',

' + . '

You have a missed payment. Please pay to avoid penalty.

'; $ok = $this->emailService->send($email, $subject, $body, 'finance'); $ok ? $sent++ : $failed++; } diff --git a/app/Services/Payments/PaymentNotificationDispatchService.php b/app/Services/Payments/PaymentNotificationDispatchService.php index 534f58db..7bfa3d85 100644 --- a/app/Services/Payments/PaymentNotificationDispatchService.php +++ b/app/Services/Payments/PaymentNotificationDispatchService.php @@ -2,9 +2,9 @@ namespace App\Services\Payments; -use App\Models\Configuration; use App\Models\Notification; use App\Models\UserNotification; +use App\Models\Configuration; class PaymentNotificationDispatchService { diff --git a/app/Services/Payments/PaymentNotificationService.php b/app/Services/Payments/PaymentNotificationService.php index 3797cab6..935f88f1 100644 --- a/app/Services/Payments/PaymentNotificationService.php +++ b/app/Services/Payments/PaymentNotificationService.php @@ -15,19 +15,20 @@ class PaymentNotificationService public function __construct( private EmailService $emailService, private PaymentNotificationDispatchService $dispatchService - ) {} + ) { + } public function listLogs(?string $from, ?string $to, ?string $type): array { $query = PaymentNotificationLog::query()->with('parent')->orderByDesc('sent_at'); - if (! empty($from)) { + if (!empty($from)) { $query->where('sent_at', '>=', $from); } - if (! empty($to)) { + if (!empty($to)) { $query->where('sent_at', '<=', $to); } - if (! empty($type)) { + if (!empty($type)) { $query->where('type', $type); } @@ -84,17 +85,15 @@ class PaymentNotificationService $type = $this->resolveType($parentId, $schoolYear, $typeInput); - if (! $force && PaymentNotificationLog::existsForPeriod($parentId, $year, $month, $type)) { + if (!$force && PaymentNotificationLog::existsForPeriod($parentId, $year, $month, $type)) { $results['skipped']++; $results['details'][] = ['parent_id' => $parentId, 'result' => 'already_sent']; - return $results; } - if ($balance <= 0 && ! $force) { + if ($balance <= 0 && !$force) { $results['skipped']++; $results['details'][] = ['parent_id' => $parentId, 'result' => 'no_balance']; - return $results; } @@ -229,13 +228,13 @@ class PaymentNotificationService private function composeMessage(int $parentId, float $balance, string $schoolYear, \DateTime $now): array { $user = User::query()->find($parentId); - $parentName = $user ? trim(($user->firstname ?? '').' '.($user->lastname ?? '')) : ''; + $parentName = $user ? trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? '')) : ''; $greeting = $parentName !== '' ? "Dear {$parentName}," : 'Dear Parent,'; $monthYear = $now->format('F Y'); $subject = sprintf('Monthly Tuition Reminder — %s', $schoolYear); - $balanceFmt = '$'.number_format($balance, 2); - $intro = 'This is your monthly installment reminder for '.$schoolYear.'.'; + $balanceFmt = '$' . number_format($balance, 2); + $intro = 'This is your monthly installment reminder for ' . $schoolYear . '.'; $installmentInfo = $this->computeInstallmentSuggestion($balance); @@ -299,14 +298,14 @@ class PaymentNotificationService 'remaining_installments' => $remainingInstallments, 'max_installments' => $maxInstallments, 'installment_due' => round($installmentDue, 2), - 'installment_due_fmt' => '$'.number_format($installmentDue, 2), + 'installment_due_fmt' => '$' . number_format($installmentDue, 2), ]; } private function getSecondaryGuardianEmail(int $primaryUserId): ?string { $row = DB::table('family_guardians')->where('user_id', $primaryUserId)->first(); - if (! $row || empty($row->family_id)) { + if (!$row || empty($row->family_id)) { return null; } @@ -331,10 +330,9 @@ class PaymentNotificationService private function getUserEmail(int $userId): ?string { $email = (string) (DB::table('users')->where('id', $userId)->value('email') ?? ''); - if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL)) { + if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) { return null; } - return $email; } @@ -355,7 +353,7 @@ class PaymentNotificationService ); } } catch (\Throwable $e) { - Log::warning('Unable to notify heads of finance: '.$e->getMessage()); + Log::warning('Unable to notify heads of finance: ' . $e->getMessage()); } } @@ -364,10 +362,9 @@ class PaymentNotificationService $base['sent'] += $update['sent'] ?? 0; $base['skipped'] += $update['skipped'] ?? 0; $base['failed'] += $update['failed'] ?? 0; - if (! empty($update['details'])) { + if (!empty($update['details'])) { $base['details'] = array_merge($base['details'], $update['details']); } - return $base; } @@ -388,7 +385,6 @@ class PaymentNotificationService if (function_exists('user_timezone')) { return (string) user_timezone(); } - return (string) (config('app.timezone') ?: 'UTC'); } } diff --git a/app/Services/Payments/PaymentTestNotificationService.php b/app/Services/Payments/PaymentTestNotificationService.php index 0d9ac2e9..1ab86176 100644 --- a/app/Services/Payments/PaymentTestNotificationService.php +++ b/app/Services/Payments/PaymentTestNotificationService.php @@ -14,12 +14,14 @@ use DateTimeZone; class PaymentTestNotificationService { - public function __construct(private EmailService $emailService) {} + public function __construct(private EmailService $emailService) + { + } public function send(string $email, string $type = 'no_payment'): array { $email = trim($email); - if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL)) { + if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) { return ['ok' => false, 'message' => 'Invalid email address.']; } @@ -51,11 +53,11 @@ class PaymentTestNotificationService $ccEmail = $this->findSecondaryGuardianEmail($parentId, $email); - $parentName = $user ? trim(($user->firstname ?? '').' '.($user->lastname ?? '')) : ''; + $parentName = $user ? trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? '')) : ''; $monthYear = $now->format('F Y'); $subject = sprintf('Monthly Tuition Reminder — %s', $schoolYear); $greeting = $parentName !== '' ? "Dear {$parentName}," : 'Dear Parent,'; - $balanceFmt = '$'.number_format($totalBalance, 2); + $balanceFmt = '$' . number_format($totalBalance, 2); $intro = ($type === 'no_payment') ? "We noticed there are outstanding tuition charges for {$schoolYear} but no payment has been recorded yet." : "This is your monthly installment reminder for {$schoolYear}."; @@ -77,11 +79,11 @@ class PaymentTestNotificationService HTML; - $bodyHtml .= '
    ' - ."
  • Remaining installments: {$installmentInfo['remaining_installments']}
  • " - ."
  • Suggested installment this month: {$installmentInfo['installment_due_fmt']}
  • " - ."
  • Maximum installments available: {$installmentInfo['max_installments']}
  • " - .'
'; + $bodyHtml .= "
    " + . "
  • Remaining installments: {$installmentInfo['remaining_installments']}
  • " + . "
  • Suggested installment this month: {$installmentInfo['installment_due_fmt']}
  • " + . "
  • Maximum installments available: {$installmentInfo['max_installments']}
  • " + . "
"; $body = MailHtml::document('Monthly Tuition Reminder', $bodyHtml); @@ -166,7 +168,7 @@ class PaymentTestNotificationService 'remaining_installments' => $remainingInstallments, 'max_installments' => $maxInstallments, 'installment_due' => round($installmentDue, 2), - 'installment_due_fmt' => '$'.number_format($installmentDue, 2), + 'installment_due_fmt' => '$' . number_format($installmentDue, 2), ]; } @@ -177,7 +179,7 @@ class PaymentTestNotificationService } $row = FamilyGuardian::query()->where('user_id', $parentId)->first(); - if (! $row || empty($row->family_id)) { + if (!$row || empty($row->family_id)) { return null; } diff --git a/app/Services/Payments/PaymentTransactionService.php b/app/Services/Payments/PaymentTransactionService.php index 5138045a..0c011e0e 100644 --- a/app/Services/Payments/PaymentTransactionService.php +++ b/app/Services/Payments/PaymentTransactionService.php @@ -17,7 +17,7 @@ class PaymentTransactionService 'payment_status' => $payload['payment_status'] ?? 'Pending', 'transaction_fee' => $payload['transaction_fee'] ?? null, 'payment_reference' => $payload['payment_reference'] ?? null, - 'is_full_payment' => ! empty($payload['is_full_payment']), + 'is_full_payment' => !empty($payload['is_full_payment']), 'school_year' => $payload['school_year'] ?? null, 'semester' => $payload['semester'] ?? null, ]; diff --git a/app/Services/Payments/PaypalPaymentService.php b/app/Services/Payments/PaypalPaymentService.php index ea6bae73..359d573b 100644 --- a/app/Services/Payments/PaypalPaymentService.php +++ b/app/Services/Payments/PaypalPaymentService.php @@ -6,19 +6,13 @@ use App\Models\Payment; use App\Services\ApplicationUrlService; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Log; -use PayPal\Api\Amount; -use PayPal\Api\Payer; -use PayPal\Api\PaymentExecution; -use PayPal\Api\RedirectUrls; -use PayPal\Api\Transaction; -use PayPal\Auth\OAuthTokenCredential; -use PayPal\Rest\ApiContext; class PaypalPaymentService { public function __construct( private ApplicationUrlService $urls, - ) {} + ) { + } public function getRedirectUrl(): string { @@ -30,11 +24,11 @@ class PaypalPaymentService public function createPayment(int $paymentId): array { $payment = Payment::query()->find($paymentId); - if (! $payment) { + if (!$payment) { throw new \RuntimeException('Payment not found.'); } - if (! $this->sdkAvailable()) { + if (!$this->sdkAvailable()) { return [ 'redirect_url' => $this->getRedirectUrl(), 'mode' => 'hosted', @@ -45,23 +39,23 @@ class PaypalPaymentService try { $apiContext = $this->buildApiContext(); - $payer = new Payer; + $payer = new \PayPal\Api\Payer(); $payer->setPaymentMethod('paypal'); - $amount = new Amount; + $amount = new \PayPal\Api\Amount(); $amount->setCurrency('USD')->setTotal($payment->balance ?? $payment->total_amount ?? 0); - $transaction = new Transaction; + $transaction = new \PayPal\Api\Transaction(); $transaction->setAmount($amount) ->setDescription('Payment for school fees') ->setInvoiceNumber(uniqid('inv_', true)); - $paypalPayment = new \PayPal\Api\Payment; + $paypalPayment = new \PayPal\Api\Payment(); $paypalPayment->setIntent('sale') ->setPayer($payer) ->setTransactions([$transaction]); - $redirectUrls = new RedirectUrls; + $redirectUrls = new \PayPal\Api\RedirectUrls(); $redirectUrls->setReturnUrl($this->urls->paypalExecuteReturnUrl()) ->setCancelUrl($this->urls->paypalCancelUrl()); @@ -77,14 +71,14 @@ class PaypalPaymentService 'payment_id' => $paymentId, ]; } catch (\Throwable $e) { - Log::error('PayPal create payment failed: '.$e->getMessage()); + Log::error('PayPal create payment failed: ' . $e->getMessage()); throw new \RuntimeException('Unable to create PayPal payment.'); } } public function executePayment(string $payerId, ?string $paypalPaymentId = null, ?int $paymentId = null): void { - if (! $this->sdkAvailable()) { + if (!$this->sdkAvailable()) { throw new \RuntimeException('PayPal SDK not installed.'); } @@ -95,13 +89,13 @@ class PaypalPaymentService $apiContext = $this->buildApiContext(); $payment = \PayPal\Api\Payment::get($paypalId, $apiContext); - $execution = new PaymentExecution; + $execution = new \PayPal\Api\PaymentExecution(); $execution->setPayerId($payerId); $payment->execute($execution, $apiContext); $internalPaymentId = $paymentId; - if (! $internalPaymentId && $paypalId !== '') { + if (!$internalPaymentId && $paypalId !== '') { $internalPaymentId = (int) Cache::get($this->cacheKey($paypalId)); } if ($internalPaymentId) { @@ -119,18 +113,18 @@ class PaypalPaymentService private function sdkAvailable(): bool { - return class_exists(ApiContext::class) - && class_exists(OAuthTokenCredential::class); + return class_exists(\PayPal\Rest\ApiContext::class) + && class_exists(\PayPal\Auth\OAuthTokenCredential::class); } - private function buildApiContext(): ApiContext + private function buildApiContext(): \PayPal\Rest\ApiContext { $clientId = (string) (config('services.paypal.client_id') ?: env('PAYPAL_CLIENT_ID')); $secret = (string) (config('services.paypal.secret') ?: env('PAYPAL_SECRET')); $mode = (string) (config('services.paypal.mode') ?: env('PAYPAL_MODE') ?: 'sandbox'); - $apiContext = new ApiContext( - new OAuthTokenCredential($clientId, $secret) + $apiContext = new \PayPal\Rest\ApiContext( + new \PayPal\Auth\OAuthTokenCredential($clientId, $secret) ); $apiContext->setConfig([ @@ -143,6 +137,6 @@ class PaypalPaymentService private function cacheKey(string $paypalPaymentId): string { - return 'paypal_payment:'.$paypalPaymentId; + return 'paypal_payment:' . $paypalPaymentId; } } diff --git a/app/Services/Payments/PaypalPaymentSyncService.php b/app/Services/Payments/PaypalPaymentSyncService.php index 65a1266a..01b9bcbf 100644 --- a/app/Services/Payments/PaypalPaymentSyncService.php +++ b/app/Services/Payments/PaypalPaymentSyncService.php @@ -5,8 +5,8 @@ namespace App\Services\Payments; use App\Models\Configuration; use App\Models\Enrollment; use App\Models\Invoice; -use App\Models\Payment; use App\Models\PayPalPayment; +use App\Models\Payment; use App\Models\Student; use App\Models\User; use App\Services\EmailService; @@ -14,7 +14,9 @@ use Illuminate\Support\Facades\Log; class PaypalPaymentSyncService { - public function __construct(private EmailService $emailService) {} + public function __construct(private EmailService $emailService) + { + } public function sync(bool $dryRun = false, bool $reportOnly = false): array { @@ -34,16 +36,15 @@ class PaypalPaymentSyncService $failed = []; foreach ($entries as $entry) { - if (! $reportOnly) { + if (!$reportOnly) { $entry->sync_attempts = (int) $entry->sync_attempts + 1; $entry->save(); } $user = User::query()->where('school_id', $entry->parent_school_id)->first(); - if (! $user) { + if (!$user) { $failed[] = (string) $entry->transaction_id; Log::error('PayPal sync: no user for parent_school_id', ['parent_school_id' => $entry->parent_school_id]); - continue; } @@ -53,12 +54,11 @@ class PaypalPaymentSyncService ->latest('created_at') ->first(); - if (! $reportOnly && ! $dryRun) { + if (!$reportOnly && !$dryRun) { if ($invoice) { $ok = $this->applyPayment($invoice, $entry->amount, (string) $entry->transaction_id, $schoolYear, $semester, $entry->created_at); - if (! $ok) { + if (!$ok) { $failed[] = (string) $entry->transaction_id; - continue; } } else { @@ -106,7 +106,7 @@ class PaypalPaymentSyncService $invoice->status = 'Paid'; } - if (! $invoice->save()) { + if (!$invoice->save()) { return false; } @@ -135,7 +135,7 @@ class PaypalPaymentSyncService private function updateEnrollmentStatusIfPaid(int $invoiceId, string $schoolYear): void { $invoice = Invoice::query()->find($invoiceId); - if (! $invoice || (float) $invoice->balance > 0) { + if (!$invoice || (float) $invoice->balance > 0) { return; } @@ -155,16 +155,15 @@ class PaypalPaymentSyncService { if ($processed === 0 && empty($failed)) { Log::info("[{$mode}] No PayPal sync updates."); - return; } - $subject = "[{$mode}] PayPal Sync Report - ".now()->format('Y-m-d H:i'); + $subject = "[{$mode}] PayPal Sync Report - " . now()->format('Y-m-d H:i'); $body = "PayPal Sync Mode: {$mode}\n\n"; $body .= "{$processed} PayPal payments processed.\n\n"; - if (! empty($failed)) { - $body .= count($failed)." failed transactions:\n".implode("\n", $failed); + if (!empty($failed)) { + $body .= count($failed) . " failed transactions:\n" . implode("\n", $failed); } else { $body .= "No failed transactions.\n"; } diff --git a/app/Services/Payments/PaypalTransactionsService.php b/app/Services/Payments/PaypalTransactionsService.php index 9e0fd78e..096678a1 100644 --- a/app/Services/Payments/PaypalTransactionsService.php +++ b/app/Services/Payments/PaypalTransactionsService.php @@ -12,11 +12,11 @@ class PaypalTransactionsService if ($keyword) { $query->where(function ($q) use ($keyword) { - $q->where('transaction_id', 'like', '%'.$keyword.'%') - ->orWhere('payer_email', 'like', '%'.$keyword.'%') - ->orWhere('event_type', 'like', '%'.$keyword.'%') - ->orWhere('order_id', 'like', '%'.$keyword.'%') - ->orWhere('parent_school_id', 'like', '%'.$keyword.'%'); + $q->where('transaction_id', 'like', '%' . $keyword . '%') + ->orWhere('payer_email', 'like', '%' . $keyword . '%') + ->orWhere('event_type', 'like', '%' . $keyword . '%') + ->orWhere('order_id', 'like', '%' . $keyword . '%') + ->orWhere('parent_school_id', 'like', '%' . $keyword . '%'); }); } @@ -29,11 +29,11 @@ class PaypalTransactionsService if ($keyword) { $query->where(function ($q) use ($keyword) { - $q->where('transaction_id', 'like', '%'.$keyword.'%') - ->orWhere('payer_email', 'like', '%'.$keyword.'%') - ->orWhere('event_type', 'like', '%'.$keyword.'%') - ->orWhere('order_id', 'like', '%'.$keyword.'%') - ->orWhere('parent_school_id', 'like', '%'.$keyword.'%'); + $q->where('transaction_id', 'like', '%' . $keyword . '%') + ->orWhere('payer_email', 'like', '%' . $keyword . '%') + ->orWhere('event_type', 'like', '%' . $keyword . '%') + ->orWhere('order_id', 'like', '%' . $keyword . '%') + ->orWhere('parent_school_id', 'like', '%' . $keyword . '%'); }); } diff --git a/app/Services/Policy/PolicyContentService.php b/app/Services/Policy/PolicyContentService.php index 4d7cee33..365b1e0f 100644 --- a/app/Services/Policy/PolicyContentService.php +++ b/app/Services/Policy/PolicyContentService.php @@ -14,16 +14,15 @@ class PolicyContentService public function getPolicy(string $type): array { $type = strtolower(trim($type)); - if (! isset(self::TYPES[$type])) { + if (!isset(self::TYPES[$type])) { throw new \InvalidArgumentException('Unsupported policy type.'); } $filename = self::TYPES[$type]; - $path = resource_path('policies/'.$filename); + $path = resource_path('policies/' . $filename); - if (! is_file($path)) { + if (!is_file($path)) { Log::warning('Policy file missing.', ['type' => $type, 'path' => $path]); - return [ 'type' => $type, 'title' => $this->titleFor($type), diff --git a/app/Services/Preferences/PreferencesCommandService.php b/app/Services/Preferences/PreferencesCommandService.php index 11ac3e57..ff629909 100644 --- a/app/Services/Preferences/PreferencesCommandService.php +++ b/app/Services/Preferences/PreferencesCommandService.php @@ -7,7 +7,9 @@ use Illuminate\Support\Facades\DB; class PreferencesCommandService { - public function __construct(private PreferencesOptionsService $options) {} + public function __construct(private PreferencesOptionsService $options) + { + } public function upsert(int $userId, array $payload): Preferences { @@ -20,7 +22,6 @@ class PreferencesCommandService if ($existing) { $existing->fill($data); $existing->save(); - return $existing->refresh(); } diff --git a/app/Services/Preferences/PreferencesOptionsService.php b/app/Services/Preferences/PreferencesOptionsService.php index 9b4fee2c..09cf286f 100644 --- a/app/Services/Preferences/PreferencesOptionsService.php +++ b/app/Services/Preferences/PreferencesOptionsService.php @@ -28,23 +28,21 @@ class PreferencesOptionsService public function normalizeStyle(?string $style): ?string { - if (! $style) { + if (!$style) { return null; } $style = trim($style); - return in_array($style, $this->styleOptions(), true) ? $style : null; } public function normalizeMenu(?string $menu): ?string { - if (! $menu) { + if (!$menu) { return null; } $menu = trim($menu); - return in_array($menu, $this->menuOptions(), true) ? $menu : null; } } diff --git a/app/Services/Preferences/PreferencesQueryService.php b/app/Services/Preferences/PreferencesQueryService.php index 34b7ed74..bd546226 100644 --- a/app/Services/Preferences/PreferencesQueryService.php +++ b/app/Services/Preferences/PreferencesQueryService.php @@ -7,14 +7,16 @@ use Illuminate\Contracts\Pagination\LengthAwarePaginator; class PreferencesQueryService { - public function __construct(private PreferencesOptionsService $options) {} + public function __construct(private PreferencesOptionsService $options) + { + } public function getForUser(int $userId): array { $row = Preferences::query()->where('user_id', $userId)->first(); $base = $this->options->defaultPreferences(); - if (! $row) { + if (!$row) { return [ 'preferences' => $base, 'options' => $this->optionsPayload(), @@ -33,12 +35,12 @@ class PreferencesQueryService ->leftJoin('users', 'users.id', '=', 'user_preferences.user_id') ->select('user_preferences.*', 'users.firstname', 'users.lastname', 'users.email'); - if (! empty($filters['user_id'])) { + if (!empty($filters['user_id'])) { $query->where('user_preferences.user_id', (int) $filters['user_id']); } - if (! empty($filters['q'])) { - $term = '%'.strtolower(trim((string) $filters['q'])).'%'; + if (!empty($filters['q'])) { + $term = '%' . strtolower(trim((string) $filters['q'])) . '%'; $query->where(function ($q) use ($term) { $q->whereRaw('LOWER(users.firstname) LIKE ?', [$term]) ->orWhereRaw('LOWER(users.lastname) LIKE ?', [$term]) @@ -51,7 +53,7 @@ class PreferencesQueryService $allowedSorts = ['updated_at', 'created_at', 'user_id']; if (in_array($sortBy, $allowedSorts, true)) { - $query->orderBy('user_preferences.'.$sortBy, $sortDir); + $query->orderBy('user_preferences.' . $sortBy, $sortDir); } else { $query->orderBy('user_preferences.updated_at', 'desc'); } diff --git a/app/Services/PrintRequests/PrintRequestsPortalService.php b/app/Services/PrintRequests/PrintRequestsPortalService.php index a1b23838..504a6ddb 100644 --- a/app/Services/PrintRequests/PrintRequestsPortalService.php +++ b/app/Services/PrintRequests/PrintRequestsPortalService.php @@ -2,7 +2,6 @@ namespace App\Services\PrintRequests; -use App\Controllers\PrintRequests; use App\Models\AdminNotificationSubject; use App\Models\ClassSection; use App\Models\Configuration; @@ -17,7 +16,7 @@ use Illuminate\Support\Facades\Schema; use Illuminate\Support\Str; /** - * legacy {@see PrintRequests} parity (SPA JSON + uploads). + * legacy {@see \App\Controllers\PrintRequests} parity (SPA JSON + uploads). */ class PrintRequestsPortalService { @@ -166,7 +165,7 @@ class PrintRequestsPortalService } /** - * @param array $requestData merged row after update for notifications + * @param array $requestData merged row after update for notifications */ public function notifyAdminsForPrintRequest(int $printRequestId, array $requestData, string $event = 'created'): void { @@ -324,7 +323,7 @@ class PrintRequestsPortalService } /** - * @param array $row + * @param array $row * @return array */ public function normalizePrintRequestRow(array $row): array diff --git a/app/Services/Promotions/LevelProgressionService.php b/app/Services/Promotions/LevelProgressionService.php index c85e75f7..60b42182 100644 --- a/app/Services/Promotions/LevelProgressionService.php +++ b/app/Services/Promotions/LevelProgressionService.php @@ -5,7 +5,6 @@ namespace App\Services\Promotions; use App\Models\ClassSection; use App\Models\LevelProgression; use App\Models\SchoolClass; -use App\Services\School\AccountEventService; use Illuminate\Support\Collection; /** @@ -13,7 +12,7 @@ use Illuminate\Support\Collection; * `level_progressions` table (plan section 10). * * Falls back to `class_id + 1` only if no mapping is found, matching - * the legacy behaviour in {@see AccountEventService}. + * the legacy behaviour in {@see \App\Services\School\AccountEventService}. */ class LevelProgressionService { @@ -24,15 +23,15 @@ class LevelProgressionService public const DEFAULT_MAP = [ ['current' => 'KG1', 'next' => 'KG2', 'order' => 10, 'terminal' => false], ['current' => 'KG2', 'next' => 'Grade 1', 'order' => 20, 'terminal' => false], - ['current' => 'Grade 1', 'next' => 'Grade 2', 'order' => 30, 'terminal' => false], - ['current' => 'Grade 2', 'next' => 'Grade 3', 'order' => 40, 'terminal' => false], - ['current' => 'Grade 3', 'next' => 'Grade 4', 'order' => 50, 'terminal' => false], - ['current' => 'Grade 4', 'next' => 'Grade 5', 'order' => 60, 'terminal' => false], - ['current' => 'Grade 5', 'next' => 'Grade 6', 'order' => 70, 'terminal' => false], - ['current' => 'Grade 6', 'next' => 'Grade 7', 'order' => 80, 'terminal' => false], - ['current' => 'Grade 7', 'next' => 'Grade 8', 'order' => 90, 'terminal' => false], - ['current' => 'Grade 8', 'next' => 'Grade 9', 'order' => 100, 'terminal' => false], - ['current' => 'Grade 9', 'next' => 'Youth', 'order' => 110, 'terminal' => false], + ['current' => 'Grade 1','next' => 'Grade 2', 'order' => 30, 'terminal' => false], + ['current' => 'Grade 2','next' => 'Grade 3', 'order' => 40, 'terminal' => false], + ['current' => 'Grade 3','next' => 'Grade 4', 'order' => 50, 'terminal' => false], + ['current' => 'Grade 4','next' => 'Grade 5', 'order' => 60, 'terminal' => false], + ['current' => 'Grade 5','next' => 'Grade 6', 'order' => 70, 'terminal' => false], + ['current' => 'Grade 6','next' => 'Grade 7', 'order' => 80, 'terminal' => false], + ['current' => 'Grade 7','next' => 'Grade 8', 'order' => 90, 'terminal' => false], + ['current' => 'Grade 8','next' => 'Grade 9', 'order' => 100, 'terminal' => false], + ['current' => 'Grade 9','next' => 'Youth', 'order' => 110, 'terminal' => false], ['current' => 'Youth', 'next' => null, 'order' => 120, 'terminal' => true], ]; @@ -78,7 +77,7 @@ class LevelProgressionService } $current = SchoolClass::query()->find($currentClassId); - if (! $current) { + if (!$current) { return null; } $currentName = (string) ($current->class_name ?? ''); @@ -119,10 +118,9 @@ class LevelProgressionService return null; } $classId = ClassSection::getClassId($classSectionId); - if (! $classId) { + if (!$classId) { return null; } - return $this->resolveByCurrentClassId((int) $classId); } @@ -183,7 +181,6 @@ class LevelProgressionService if ($existing) { $existing->fill($data); $existing->save(); - return $existing; } diff --git a/app/Services/Promotions/Placement/BalancedSectionPlacementService.php b/app/Services/Promotions/Placement/BalancedSectionPlacementService.php index 0bb8e3d6..9e193d74 100644 --- a/app/Services/Promotions/Placement/BalancedSectionPlacementService.php +++ b/app/Services/Promotions/Placement/BalancedSectionPlacementService.php @@ -45,7 +45,6 @@ class BalancedSectionPlacementService return $scoreB <=> $scoreA; } $name = strcmp((string) ($a['student_name'] ?? ''), (string) ($b['student_name'] ?? '')); - return $name !== 0 ? $name : ((int) $a['student_id'] <=> (int) $b['student_id']); }); } @@ -80,7 +79,6 @@ class BalancedSectionPlacementService for ($i = 1; $i <= $sectionCount; $i++) { $sizes[$i] = $base + ($i <= $remainder ? 1 : 0); } - return $sizes; } @@ -100,7 +98,6 @@ class BalancedSectionPlacementService if ($cmp !== 0) { return $cmp; } - return $a['section_index'] <=> $b['section_index']; }); diff --git a/app/Services/Promotions/Placement/PlacementPoolBuilder.php b/app/Services/Promotions/Placement/PlacementPoolBuilder.php index 9e5818fe..03755292 100644 --- a/app/Services/Promotions/Placement/PlacementPoolBuilder.php +++ b/app/Services/Promotions/Placement/PlacementPoolBuilder.php @@ -7,7 +7,9 @@ use Illuminate\Support\Facades\DB; class PlacementPoolBuilder { - public function __construct(private ScoreBandClassifier $bands) {} + public function __construct(private ScoreBandClassifier $bands) + { + } public function build(string $fromSchoolYear, string $toSchoolYear, ?int $toGradeLevelId = null): array { @@ -36,39 +38,34 @@ class PlacementPoolBuilder $studentId = (int) $row->student_id; if ((int) ($row->is_active ?? 1) === 0) { $exceptions['withdrawn_or_inactive_student'][] = $studentId; - continue; } if ($this->alreadyPlaced($studentId, $toSchoolYear)) { $exceptions['duplicate_target_year_placement'][] = $studentId; - continue; } - if (! $this->isPromotedDecision((string) ($row->decision ?? ''))) { + if (!$this->isPromotedDecision((string) ($row->decision ?? ''))) { $bucket = $row->decision === null ? 'missing_student_decision' : 'decision_conflicts_with_enrollment_request'; $exceptions[$bucket][] = $studentId; - continue; } $score = $row->year_score !== null ? (float) $row->year_score : ($row->final_average !== null ? (float) $row->final_average : null); if ($score === null) { $exceptions['missing_student_decision'][] = $studentId; - continue; } try { $band = $this->bands->fromScore($score, true); } catch (\RuntimeException) { $exceptions['failed_retained'][] = $studentId; - continue; } $pool[] = [ 'student_id' => $studentId, 'student_type' => 'returning', - 'student_name' => trim((string) $row->lastname.', '.(string) $row->firstname), + 'student_name' => trim((string) $row->lastname . ', ' . (string) $row->firstname), 'source_decision_id' => $row->decision_id ? (int) $row->decision_id : null, 'source_enrollment_id' => $row->enrollment_id ? (int) $row->enrollment_id : null, 'final_score' => $score, @@ -101,19 +98,17 @@ class PlacementPoolBuilder $studentId = (int) $row->student_id; if ((int) ($row->is_active ?? 1) === 0) { $exceptions['withdrawn_or_inactive_student'][] = $studentId; - continue; } if ($this->alreadyPlaced($studentId, $toSchoolYear)) { $exceptions['duplicate_target_year_placement'][] = $studentId; - continue; } $pool[] = [ 'student_id' => $studentId, 'student_type' => 'new', - 'student_name' => trim((string) $row->lastname.', '.(string) $row->firstname), + 'student_name' => trim((string) $row->lastname . ', ' . (string) $row->firstname), 'source_decision_id' => null, 'source_enrollment_id' => (int) $row->enrollment_id, 'final_score' => null, @@ -182,7 +177,6 @@ class PlacementPoolBuilder private function isPromotedDecision(string $decision): bool { $normalized = strtolower(trim($decision)); - return in_array($normalized, ['passed', 'pass', 'promoted', 'promote', 'eligible_to_continue'], true); } } diff --git a/app/Services/Promotions/Placement/PromotionSectionCapacityService.php b/app/Services/Promotions/Placement/PromotionSectionCapacityService.php index 412caf47..62770bd9 100644 --- a/app/Services/Promotions/Placement/PromotionSectionCapacityService.php +++ b/app/Services/Promotions/Placement/PromotionSectionCapacityService.php @@ -9,7 +9,6 @@ use RuntimeException; class PromotionSectionCapacityService { public const CONFIG_KEY = 'promotion.section_capacity'; - public const DEFAULT_CAPACITY = 20; public function capacity(): array @@ -24,7 +23,7 @@ class PromotionSectionCapacityService 'fallback' => self::DEFAULT_CAPACITY, ]); $value = self::DEFAULT_CAPACITY; - } elseif (! ctype_digit((string) $raw)) { + } elseif (!ctype_digit((string) $raw)) { throw new RuntimeException('promotion.section_capacity must be a positive integer.'); } else { $value = (int) $raw; diff --git a/app/Services/Promotions/Placement/SectionPlacementPreviewService.php b/app/Services/Promotions/Placement/SectionPlacementPreviewService.php index 555cfea9..daa402ac 100644 --- a/app/Services/Promotions/Placement/SectionPlacementPreviewService.php +++ b/app/Services/Promotions/Placement/SectionPlacementPreviewService.php @@ -14,7 +14,8 @@ class SectionPlacementPreviewService private PromotionSectionCapacityService $capacityService, private PlacementPoolBuilder $poolBuilder, private BalancedSectionPlacementService $placementService - ) {} + ) { + } public function createDraft( string $fromSchoolYear, @@ -118,12 +119,12 @@ class SectionPlacementPreviewService ->where('is_event_only', 0) ->exists(); if ($duplicate) { - throw new RuntimeException('Student '.$studentId.' already has a target-year class placement.'); + throw new RuntimeException('Student ' . $studentId . ' already has a target-year class placement.'); } $sectionId = $sectionMap[(int) $student->planned_section_index] ?? null; if ($sectionId === null) { - throw new RuntimeException('Missing target section for planned section '.$student->planned_section_index.'.'); + throw new RuntimeException('Missing target section for planned section ' . $student->planned_section_index . '.'); } DB::table('student_class')->insert([ @@ -132,7 +133,7 @@ class SectionPlacementPreviewService 'is_event_only' => 0, 'semester' => $semester, 'school_year' => $batch->to_school_year, - 'description' => 'Finalized from section placement batch #'.$batch->getKey(), + 'description' => 'Finalized from section placement batch #' . $batch->getKey(), 'created_at' => now(), 'updated_at' => now(), 'updated_by' => $userId, @@ -153,7 +154,7 @@ class SectionPlacementPreviewService private function ensureSections(SectionPlacementBatch $batch, string $semester): array { - if (! $batch->to_grade_level_id) { + if (!$batch->to_grade_level_id) { throw new RuntimeException('to_grade_level_id is required to finalize placement sections.'); } @@ -175,7 +176,6 @@ class SectionPlacementPreviewService if ($existing) { $map[$i] = (int) $existing; - continue; } @@ -198,8 +198,7 @@ class SectionPlacementPreviewService private function sectionName(int $classId, string $suffix, string $schoolYear): string { $className = DB::table('classes')->where('id', $classId)->value('class_name'); - $base = $className ? (string) $className : ('Class '.$classId); - - return $base.'-'.$suffix.' '.$schoolYear; + $base = $className ? (string) $className : ('Class ' . $classId); + return $base . '-' . $suffix . ' ' . $schoolYear; } } diff --git a/app/Services/Promotions/PromotionEligibilityService.php b/app/Services/Promotions/PromotionEligibilityService.php index 3d2d169e..29845c89 100644 --- a/app/Services/Promotions/PromotionEligibilityService.php +++ b/app/Services/Promotions/PromotionEligibilityService.php @@ -24,12 +24,13 @@ class PromotionEligibilityService private LevelProgressionService $progression, private PromotionStatusService $statusService, private PromotionAuditService $audit - ) {} + ) { + } /** * Evaluate eligibility for a single student. * - * @param int|null $userId actor id for audit + * @param int|null $userId actor id for audit */ public function evaluateStudent( int $studentId, @@ -37,7 +38,7 @@ class PromotionEligibilityService ?int $userId = null ): ?StudentPromotionRecord { $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return null; } @@ -82,7 +83,7 @@ class PromotionEligibilityService $summary = $this->emptySummary(); foreach ($studentIds as $studentId) { $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { continue; } try { @@ -131,7 +132,7 @@ class PromotionEligibilityService $summary = $this->emptySummary(); foreach ($studentIds as $studentId) { $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { continue; } try { @@ -213,7 +214,7 @@ class PromotionEligibilityService ->first(); $isNew = $existing === null; - $record = $existing ?: new StudentPromotionRecord; + $record = $existing ?: new StudentPromotionRecord(); $record->fill([ 'student_id' => $studentId, 'parent_id' => (int) ($student->parent_id ?? 0) ?: null, @@ -287,7 +288,7 @@ class PromotionEligibilityService ->orderByDesc('id') ->first(); - if (! $decision) { + if (!$decision) { return [ 'passed' => null, 'final_average' => null, @@ -331,14 +332,14 @@ class PromotionEligibilityService return [ 'passed' => null, 'final_average' => $score, - 'notes' => 'student_decisions has unrecognized decision: '.$rawDecision, + 'notes' => 'student_decisions has unrecognized decision: ' . $rawDecision, 'has_data' => false, ]; } private function resolveStatusFromEvaluation(?bool $passed, bool $terminal, bool $hasData): string { - if (! $hasData) { + if (!$hasData) { return StudentPromotionRecord::STATUS_ON_HOLD; } if ($passed === false) { @@ -347,7 +348,6 @@ class PromotionEligibilityService if ($terminal) { return StudentPromotionRecord::STATUS_GRADUATED; } - return StudentPromotionRecord::STATUS_AWAITING_PARENT; } @@ -380,17 +380,15 @@ class PromotionEligibilityService private function resolveCurrentSchoolYear(): ?string { $year = (string) (Configuration::getConfigValueByKey('school_year') ?? ''); - return $year !== '' ? $year : null; } private function nextSchoolYear(string $current): ?string { - if (! preg_match('/^(\d{4})-(\d{4})$/', $current, $m)) { + if (!preg_match('/^(\d{4})-(\d{4})$/', $current, $m)) { return null; } - - return ((int) $m[1] + 1).'-'.((int) $m[2] + 1); + return ((int) $m[1] + 1) . '-' . ((int) $m[2] + 1); } private function passThreshold(): float @@ -399,7 +397,6 @@ class PromotionEligibilityService if ($configured !== null && is_numeric($configured)) { return (float) $configured; } - return self::DEFAULT_PASS_THRESHOLD; } } diff --git a/app/Services/Promotions/PromotionEnrollmentService.php b/app/Services/Promotions/PromotionEnrollmentService.php index 2ad07f09..b6a3c54c 100644 --- a/app/Services/Promotions/PromotionEnrollmentService.php +++ b/app/Services/Promotions/PromotionEnrollmentService.php @@ -28,7 +28,8 @@ class PromotionEnrollmentService public function __construct( private PromotionStatusService $statusService, private PromotionAuditService $audit - ) {} + ) { + } /** * Lists actionable promotion records for a parent (the parent @@ -53,9 +54,9 @@ class PromotionEnrollmentService $studentIds = $records->pluck('student_id')->unique()->all(); /** @var EloquentCollection $studentsCollection */ - $studentsCollection = ! empty($studentIds) + $studentsCollection = !empty($studentIds) ? Student::query()->whereIn('id', $studentIds)->get() - : new EloquentCollection; + : new EloquentCollection(); $studentsById = $studentsCollection->keyBy('id'); $payload = $records->map(function (StudentPromotionRecord $record) use ($studentsById) { @@ -79,7 +80,7 @@ class PromotionEnrollmentService $this->assertActionable($record); return DB::transaction(function () use ($record, $parentId, $userId) { - if (! $record->enrollment_started_at) { + if (!$record->enrollment_started_at) { $record->enrollment_started_at = now(); } $record->enrollment_status = StudentPromotionRecord::ENROLLMENT_IN_PROGRESS; @@ -116,7 +117,7 @@ class PromotionEnrollmentService $sanitized = []; foreach ($steps as $field => $value) { - if (! in_array($field, self::ALLOWED_STEPS, true)) { + if (!in_array($field, self::ALLOWED_STEPS, true)) { continue; } $sanitized[$field] = (bool) $value; @@ -138,7 +139,7 @@ class PromotionEnrollmentService return $record; } - if (! $record->enrollment_started_at) { + if (!$record->enrollment_started_at) { $record->enrollment_started_at = now(); } $record->enrollment_status = StudentPromotionRecord::ENROLLMENT_IN_PROGRESS; @@ -184,7 +185,7 @@ class PromotionEnrollmentService $this->assertParentOwns($record, $parentId); $this->assertActionable($record); - if (! $record->enrollmentChecklistComplete()) { + if (!$record->enrollmentChecklistComplete()) { throw new RuntimeException('Enrollment checklist is incomplete.'); } @@ -293,12 +294,10 @@ class PromotionEnrollmentService if ($existing) { $existing->fill($payload); $existing->save(); - return (int) $existing->getKey(); } $created = Enrollment::query()->create($payload); - return $created ? (int) $created->getKey() : null; } @@ -308,7 +307,7 @@ class PromotionEnrollmentService 'promotion_id' => (int) $record->getKey(), 'student_id' => (int) $record->student_id, 'student_name' => $student - ? trim((string) $student->firstname.' '.(string) $student->lastname) + ? trim((string) $student->firstname . ' ' . (string) $student->lastname) : null, 'current_level' => $record->current_level_name, 'promoted_level' => $record->promoted_level_name, @@ -344,13 +343,12 @@ class PromotionEnrollmentService true ); }); - if (! $actionable) { + if (!$actionable) { return null; } $level = $actionable->promoted_level_name ?: 'the next level'; $deadline = $actionable->enrollment_deadline?->toDateString(); - $deadlineText = $deadline ? 'by '.$deadline : 'as soon as possible'; - + $deadlineText = $deadline ? 'by ' . $deadline : 'as soon as possible'; return sprintf( 'Your child is eligible for promotion to %s. Please complete enrollment for the new school year %s.', $level, @@ -374,7 +372,7 @@ class PromotionEnrollmentService private function assertActionable(StudentPromotionRecord $record): void { $actionable = StudentPromotionRecord::parentActionableStatuses(); - if (! in_array($record->promotion_status, $actionable, true)) { + if (!in_array($record->promotion_status, $actionable, true)) { throw new RuntimeException(sprintf( 'Promotion record is not actionable in status "%s".', $record->promotion_status @@ -385,10 +383,9 @@ class PromotionEnrollmentService private function guessNextSchoolYear(): ?string { $current = (string) (Configuration::getConfigValueByKey('school_year') ?? ''); - if (! preg_match('/^(\d{4})-(\d{4})$/', $current, $m)) { + if (!preg_match('/^(\d{4})-(\d{4})$/', $current, $m)) { return null; } - - return ((int) $m[1] + 1).'-'.((int) $m[2] + 1); + return ((int) $m[1] + 1) . '-' . ((int) $m[2] + 1); } } diff --git a/app/Services/Promotions/PromotionQueryService.php b/app/Services/Promotions/PromotionQueryService.php index c4b99455..8cd3eb31 100644 --- a/app/Services/Promotions/PromotionQueryService.php +++ b/app/Services/Promotions/PromotionQueryService.php @@ -42,6 +42,7 @@ class PromotionQueryService * parent_action_required?: bool, * per_page?: int|null, * } $filters + * * @return array{ * data: array>, * total: int, @@ -67,12 +68,12 @@ class PromotionQueryService $studentIds = $records->pluck('student_id')->unique()->values()->all(); $parentIds = $records->pluck('parent_id')->filter()->unique()->values()->all(); - $studentsById = ! empty($studentIds) + $studentsById = !empty($studentIds) ? Student::query()->whereIn('id', $studentIds)->get()->keyBy('id') - : new EloquentCollection; - $parentsById = ! empty($parentIds) + : new EloquentCollection(); + $parentsById = !empty($parentIds) ? User::query()->whereIn('id', $parentIds)->get()->keyBy('id') - : new EloquentCollection; + : new EloquentCollection(); $rows = $records->map(function (StudentPromotionRecord $record) use ($studentsById, $parentsById) { return $this->presentAdminRow( @@ -116,7 +117,6 @@ class PromotionQueryService foreach ($rows as $row) { $counts[(string) $row->promotion_status] = (int) $row->total; } - return $counts; } @@ -133,34 +133,34 @@ class PromotionQueryService } /** - * @param Builder $query + * @param Builder $query */ private function applyFilters(Builder $query, array $filters): void { - if (! empty($filters['status'])) { + if (!empty($filters['status'])) { $statuses = is_array($filters['status']) ? $filters['status'] : [$filters['status']]; $statuses = array_values(array_filter($statuses, static fn ($s) => is_string($s) && $s !== '')); - if (! empty($statuses)) { + if (!empty($statuses)) { $query->whereIn('promotion_status', $statuses); } } - if (! empty($filters['parent_action_required'])) { + if (!empty($filters['parent_action_required'])) { $query->whereIn('promotion_status', StudentPromotionRecord::parentActionableStatuses()); } - if (! empty($filters['next_school_year'])) { + if (!empty($filters['next_school_year'])) { $query->where('next_school_year', $filters['next_school_year']); } - if (! empty($filters['current_school_year'])) { + if (!empty($filters['current_school_year'])) { $query->where('current_school_year', $filters['current_school_year']); } - if (! empty($filters['parent_id'])) { + if (!empty($filters['parent_id'])) { $query->where('parent_id', (int) $filters['parent_id']); } - if (! empty($filters['student_id'])) { + if (!empty($filters['student_id'])) { $query->where('student_id', (int) $filters['student_id']); } - if (! empty($filters['search'])) { - $search = '%'.strtolower((string) $filters['search']).'%'; + if (!empty($filters['search'])) { + $search = '%' . strtolower((string) $filters['search']) . '%'; $query->whereIn('student_id', function ($sub) use ($search) { $sub->select('id') ->from('students') @@ -182,12 +182,12 @@ class PromotionQueryService 'promotion_id' => (int) $record->getKey(), 'student_id' => (int) $record->student_id, 'student_name' => $student - ? trim((string) $student->firstname.' '.(string) $student->lastname) + ? trim((string) $student->firstname . ' ' . (string) $student->lastname) : null, 'school_id' => $student->school_id ?? null, 'parent_id' => $record->parent_id ? (int) $record->parent_id : null, 'parent_name' => $parent - ? trim((string) $parent->firstname.' '.(string) $parent->lastname) + ? trim((string) $parent->firstname . ' ' . (string) $parent->lastname) : null, 'parent_email' => $parent->email ?? null, 'current_school_year' => $record->current_school_year, diff --git a/app/Services/Promotions/PromotionReminderService.php b/app/Services/Promotions/PromotionReminderService.php index 64e030b9..5227946b 100644 --- a/app/Services/Promotions/PromotionReminderService.php +++ b/app/Services/Promotions/PromotionReminderService.php @@ -19,7 +19,7 @@ use Illuminate\Support\Facades\Log; */ class PromotionReminderService { - /** @var (callable(int, string, string, array):void)|null */ + /** @var (callable(int $userId, string $title, string $body, array $channels):void)|null */ private $dispatcher; public function __construct( @@ -40,7 +40,7 @@ class PromotionReminderService ?string $message = null, array $channels = ['in_app', 'email'] ): PromotionReminderLog { - if (! in_array($reminderType, PromotionReminderLog::ALLOWED_TYPES, true)) { + if (!in_array($reminderType, PromotionReminderLog::ALLOWED_TYPES, true)) { $reminderType = PromotionReminderLog::TYPE_MANUAL; } @@ -53,7 +53,7 @@ class PromotionReminderService '%s is eligible for promotion to %s.%s Please complete enrollment as soon as possible.', $studentName ?: 'Your child', $level, - $deadline ? ' Deadline: '.$deadline.'.' : '' + $deadline ? ' Deadline: ' . $deadline . '.' : '' ); $finalSubject = $subject ?: $defaultSubject; @@ -83,7 +83,7 @@ class PromotionReminderService $this->dispatch((int) $record->parent_id, $finalSubject, $finalMessage, $channels); } - if (! $record->parent_notified_at) { + if (!$record->parent_notified_at) { $record->parent_notified_at = now(); $record->save(); $this->audit->logParentNotified($record, $userId, $reminderType); @@ -118,7 +118,6 @@ class PromotionReminderService $type = $this->resolveReminderType($record, $now); if ($type === null) { $skipped++; - continue; } $alreadySent = PromotionReminderLog::query() @@ -127,7 +126,6 @@ class PromotionReminderService ->exists(); if ($alreadySent) { $skipped++; - continue; } try { @@ -179,24 +177,22 @@ class PromotionReminderService if ($elapsedSeconds * 2 >= $totalSeconds) { return PromotionReminderLog::TYPE_HALFWAY; } - return PromotionReminderLog::TYPE_FIRST; } private function studentName(StudentPromotionRecord $record): ?string { $student = Student::query()->find($record->student_id); - if (! $student) { + if (!$student) { return null; } - $name = trim((string) ($student->firstname ?? '').' '.(string) ($student->lastname ?? '')); - + $name = trim((string) ($student->firstname ?? '') . ' ' . (string) ($student->lastname ?? '')); return $name !== '' ? $name : null; } private function dispatch(int $userId, string $subject, string $message, array $channels): void { - if (! $this->dispatcher) { + if (!$this->dispatcher) { return; } try { diff --git a/app/Services/Promotions/PromotionStatusService.php b/app/Services/Promotions/PromotionStatusService.php index 1b61de3d..6399a451 100644 --- a/app/Services/Promotions/PromotionStatusService.php +++ b/app/Services/Promotions/PromotionStatusService.php @@ -15,7 +15,9 @@ use RuntimeException; */ class PromotionStatusService { - public function __construct(private PromotionAuditService $audit) {} + public function __construct(private PromotionAuditService $audit) + { + } /** * Map of allowed transitions from current → set of next statuses. @@ -78,11 +80,10 @@ class PromotionStatusService if ($from === $to) { return true; } - if (! in_array($to, StudentPromotionRecord::ALL_STATUSES, true)) { + if (!in_array($to, StudentPromotionRecord::ALL_STATUSES, true)) { return false; } $allowed = self::ALLOWED_TRANSITIONS[$from] ?? []; - return in_array($to, $allowed, true); } @@ -97,7 +98,7 @@ class PromotionStatusService ?int $userId = null, ?string $notes = null ): StudentPromotionRecord { - if (! in_array($newStatus, StudentPromotionRecord::ALL_STATUSES, true)) { + if (!in_array($newStatus, StudentPromotionRecord::ALL_STATUSES, true)) { throw new InvalidArgumentException(sprintf('Unknown promotion status "%s".', $newStatus)); } @@ -105,7 +106,7 @@ class PromotionStatusService if ($oldStatus === $newStatus) { return $record; } - if (! $this->canTransition($oldStatus, $newStatus)) { + if (!$this->canTransition($oldStatus, $newStatus)) { throw new RuntimeException(sprintf( 'Transition from "%s" to "%s" is not allowed.', $oldStatus, @@ -134,7 +135,7 @@ class PromotionStatusService ?int $userId = null, ?string $notes = null ): StudentPromotionRecord { - if (! in_array($newStatus, StudentPromotionRecord::ALL_STATUSES, true)) { + if (!in_array($newStatus, StudentPromotionRecord::ALL_STATUSES, true)) { throw new InvalidArgumentException(sprintf('Unknown promotion status "%s".', $newStatus)); } diff --git a/app/Services/PublicWinners/PublicWinnersPortalService.php b/app/Services/PublicWinners/PublicWinnersPortalService.php index 31484b33..95954a7c 100644 --- a/app/Services/PublicWinners/PublicWinnersPortalService.php +++ b/app/Services/PublicWinners/PublicWinnersPortalService.php @@ -2,14 +2,12 @@ namespace App\Services\PublicWinners; -use App\Controllers\WinnersController; use App\Models\ClassSection; use App\Models\Competition; -use Carbon\CarbonInterface; use Illuminate\Support\Facades\DB; /** - * legacy {@see WinnersController} — public published winners pages. + * legacy {@see \App\Controllers\WinnersController} — public published winners pages. */ class PublicWinnersPortalService { @@ -106,7 +104,7 @@ class PublicWinnersPortalService { $arr = $c->toArray(); foreach ($arr as $key => $value) { - if ($value instanceof CarbonInterface) { + if ($value instanceof \Carbon\CarbonInterface) { $arr[$key] = $value->format('Y-m-d H:i:s'); } } diff --git a/app/Services/PurchaseOrders/PurchaseOrderCreateService.php b/app/Services/PurchaseOrders/PurchaseOrderCreateService.php index 1729b15c..c7776451 100644 --- a/app/Services/PurchaseOrders/PurchaseOrderCreateService.php +++ b/app/Services/PurchaseOrders/PurchaseOrderCreateService.php @@ -12,7 +12,7 @@ class PurchaseOrderCreateService public function create(array $payload): PurchaseOrder { $itemsPayload = $payload['items'] ?? []; - if (empty($itemsPayload) || ! is_array($itemsPayload)) { + if (empty($itemsPayload) || !is_array($itemsPayload)) { throw new RuntimeException('Add at least one line item.'); } diff --git a/app/Services/PurchaseOrders/PurchaseOrderQueryService.php b/app/Services/PurchaseOrders/PurchaseOrderQueryService.php index 22145d57..7bdab684 100644 --- a/app/Services/PurchaseOrders/PurchaseOrderQueryService.php +++ b/app/Services/PurchaseOrders/PurchaseOrderQueryService.php @@ -45,7 +45,7 @@ class PurchaseOrderQueryService ->where('purchase_orders.id', $id) ->first(); - if (! $po) { + if (!$po) { return null; } diff --git a/app/Services/PurchaseOrders/PurchaseOrderReceiveService.php b/app/Services/PurchaseOrders/PurchaseOrderReceiveService.php index b919b5a3..7539f623 100644 --- a/app/Services/PurchaseOrders/PurchaseOrderReceiveService.php +++ b/app/Services/PurchaseOrders/PurchaseOrderReceiveService.php @@ -14,7 +14,7 @@ class PurchaseOrderReceiveService public function receive(int $poId, array $received, string $issuedBy): array { $po = PurchaseOrder::query()->find($poId); - if (! $po || in_array($po->status, [PurchaseOrder::STATUS_CANCELED, PurchaseOrder::STATUS_RECEIVED], true)) { + if (!$po || in_array($po->status, [PurchaseOrder::STATUS_CANCELED, PurchaseOrder::STATUS_RECEIVED], true)) { throw new RuntimeException('PO not receivable.'); } @@ -37,9 +37,8 @@ class PurchaseOrderReceiveService ->where('id', $itemId) ->first(); - if (! $poItem) { + if (!$poItem) { $completed = false; - continue; } @@ -53,9 +52,8 @@ class PurchaseOrderReceiveService $poItem->save(); $supply = Supply::query()->find($poItem->supply_id); - if (! $supply) { + if (!$supply) { $completed = false; - continue; } @@ -66,7 +64,7 @@ class PurchaseOrderReceiveService 'supply_id' => $supply->id, 'type' => 'in', 'quantity' => $toReceive, - 'ref' => 'PO '.($po->po_number ?? $po->id), + 'ref' => 'PO ' . ($po->po_number ?? $po->id), 'issued_to' => 'Inventory', 'issued_by' => $issuedBy, 'notes' => 'Received against PO', diff --git a/app/Services/PurchaseOrders/PurchaseOrderStatusService.php b/app/Services/PurchaseOrders/PurchaseOrderStatusService.php index 5eeae0d0..3a417589 100644 --- a/app/Services/PurchaseOrders/PurchaseOrderStatusService.php +++ b/app/Services/PurchaseOrders/PurchaseOrderStatusService.php @@ -10,7 +10,7 @@ class PurchaseOrderStatusService public function cancel(int $poId): PurchaseOrder { $po = PurchaseOrder::query()->find($poId); - if (! $po || $po->status === PurchaseOrder::STATUS_RECEIVED) { + if (!$po || $po->status === PurchaseOrder::STATUS_RECEIVED) { throw new RuntimeException('Cannot cancel this PO.'); } diff --git a/app/Services/Refunds/RefundDecisionService.php b/app/Services/Refunds/RefundDecisionService.php index 75808864..c57baddf 100644 --- a/app/Services/Refunds/RefundDecisionService.php +++ b/app/Services/Refunds/RefundDecisionService.php @@ -9,11 +9,11 @@ class RefundDecisionService public function updateDecision(int $refundId, string $status, string $reason, int $actorId): array { $refund = Refund::query()->find($refundId); - if (! $refund) { + if (!$refund) { return ['ok' => false, 'message' => 'Refund not found.']; } - if (! in_array($status, [Refund::STATUS_APPROVED, Refund::STATUS_REJECTED], true)) { + if (!in_array($status, [Refund::STATUS_APPROVED, Refund::STATUS_REJECTED], true)) { return ['ok' => false, 'message' => 'Invalid refund status.']; } @@ -46,7 +46,7 @@ class RefundDecisionService public function cancel(int $refundId, int $actorId): array { $refund = Refund::query()->find($refundId); - if (! $refund) { + if (!$refund) { return ['ok' => false, 'message' => 'Refund not found.']; } diff --git a/app/Services/Refunds/RefundInvoiceAdjustmentService.php b/app/Services/Refunds/RefundInvoiceAdjustmentService.php index c5dd0345..ecccc8ae 100644 --- a/app/Services/Refunds/RefundInvoiceAdjustmentService.php +++ b/app/Services/Refunds/RefundInvoiceAdjustmentService.php @@ -8,7 +8,9 @@ use App\Services\Discounts\DiscountInvoiceService; class RefundInvoiceAdjustmentService { - public function __construct(private DiscountInvoiceService $invoiceService) {} + public function __construct(private DiscountInvoiceService $invoiceService) + { + } public function applyBookChargeAndUpdateInvoice( Invoice $invoice, @@ -21,7 +23,7 @@ class RefundInvoiceAdjustmentService $bookChargeDesc = 'Book fee retained for withdrawals before the refund deadline.'; $bookPrice = (float) ($refundDetails['book_price'] ?? 0.0); - $eligible = ! empty($refundDetails['eligible']); + $eligible = !empty($refundDetails['eligible']); $bookChargeDelta = 0.0; $bookChargeAction = 'none'; diff --git a/app/Services/Refunds/RefundOverpaymentService.php b/app/Services/Refunds/RefundOverpaymentService.php index f3e452df..bd349a52 100644 --- a/app/Services/Refunds/RefundOverpaymentService.php +++ b/app/Services/Refunds/RefundOverpaymentService.php @@ -15,7 +15,8 @@ class RefundOverpaymentService public function __construct( private RefundNotificationService $notifications, private ApplicationUrlService $urls, - ) {} + ) { + } public function recalculate(bool $triggerEvents = false, ?string $invoiceNumber = null, ?int $actorId = null): array { @@ -76,7 +77,7 @@ class RefundOverpaymentService private function recalculateForInvoice(string $invoiceNumber, bool $triggerEvents, ?int $actorId): array { $invoice = Invoice::query()->where('invoice_number', $invoiceNumber)->first(); - if (! $invoice) { + if (!$invoice) { return ['ok' => false, 'message' => 'Invoice not found.']; } @@ -120,7 +121,6 @@ class RefundOverpaymentService 'updated_at' => utc_now(), 'updated_by' => $actorId, ]); - return ['ok' => true, 'message' => 'Overpayment updated for invoice.']; } @@ -164,22 +164,27 @@ class RefundOverpaymentService ->select('id', 'parent_id', 'total_amount', 'school_year') ->where('school_year', $schoolYear) ->get() - ->map(fn ($row) => (array) $row) + ->map(fn ($row) => method_exists($row, 'toArray') ? $row->toArray() : (array) $row) + ->filter(fn (array $row) => isset($row['id'], $row['parent_id'])) + ->values() ->all(); if (empty($invRows)) { return ['created_ids' => [], 'updated_ids' => []]; } - $invoiceIds = array_map(static fn ($row) => (int) $row['id'], $invRows); + $invoiceIds = array_values(array_filter(array_map(static fn ($row) => (int) ($row['id'] ?? 0), $invRows))); $paidByInv = $this->sumPaymentsByInvoice($invoiceIds); $discByInv = $this->sumDiscountsByInvoice($invoiceIds); $refByInv = $this->sumRefundsByInvoice($invoiceIds); foreach ($invRows as $inv) { - $iid = (int) $inv['id']; - $pid = (int) $inv['parent_id']; + $iid = (int) ($inv['id'] ?? 0); + $pid = (int) ($inv['parent_id'] ?? 0); + if ($iid <= 0 || $pid <= 0) { + continue; + } $total = (float) ($inv['total_amount'] ?? 0); $paid = (float) ($paidByInv[$iid] ?? 0); $disc = (float) ($discByInv[$iid] ?? 0); @@ -204,7 +209,6 @@ class RefundOverpaymentService 'updated_by' => $actorId, ]); $updated[] = (int) $openRow->id; - continue; } @@ -225,7 +229,6 @@ class RefundOverpaymentService 'updated_by' => $actorId, ]); $updated[] = (int) $parentLevelOpen->id; - continue; } @@ -236,7 +239,7 @@ class RefundOverpaymentService ->orderByDesc('id') ->first(); - if (! $existing || $existing->status === Refund::STATUS_PAID) { + if (!$existing || $existing->status === Refund::STATUS_PAID) { $refund = Refund::query()->create([ 'parent_id' => $pid, 'school_year' => $schoolYear, diff --git a/app/Services/Refunds/RefundPayoutService.php b/app/Services/Refunds/RefundPayoutService.php index 0a6ec0e3..33a687c1 100644 --- a/app/Services/Refunds/RefundPayoutService.php +++ b/app/Services/Refunds/RefundPayoutService.php @@ -14,11 +14,11 @@ class RefundPayoutService public function recordPayment(int $refundId, array $payload, int $actorId): array { $refund = Refund::query()->find($refundId); - if (! $refund) { + if (!$refund) { return ['ok' => false, 'message' => 'Refund not found.']; } - if (! in_array($refund->status, [Refund::STATUS_APPROVED, Refund::STATUS_PARTIAL], true)) { + if (!in_array($refund->status, [Refund::STATUS_APPROVED, Refund::STATUS_PARTIAL], true)) { return ['ok' => false, 'message' => 'Refund must be Approved or Partial to pay.']; } @@ -126,7 +126,6 @@ class RefundPayoutService return $latest ? (int) $latest->id : null; } catch (\Throwable $e) { Log::warning('Refund invoice assignment failed.', ['error' => $e->getMessage()]); - return null; } } diff --git a/app/Services/Refunds/RefundPolicyService.php b/app/Services/Refunds/RefundPolicyService.php index 62aa28c8..2e0f4757 100644 --- a/app/Services/Refunds/RefundPolicyService.php +++ b/app/Services/Refunds/RefundPolicyService.php @@ -14,7 +14,8 @@ class RefundPolicyService public function __construct( private FeeRefundDetailService $refundDetails, private RefundInvoiceAdjustmentService $invoiceAdjustments - ) {} + ) { + } public function processWithdrawalRefund( int $parentId, @@ -38,7 +39,7 @@ class RefundPolicyService ->orderByDesc('created_at') ->first(); - if (! $invoice) { + if (!$invoice) { return ['ok' => false, 'error' => 'No invoice found for refund processing.']; } @@ -115,14 +116,14 @@ class RefundPolicyService $refundAmount = (float) ($details['refund_amount'] ?? 0.0); $debitAmount = (float) ($details['debit_amount'] ?? 0.0); - $eligible = ! empty($details['eligible']); + $eligible = !empty($details['eligible']); $status = $refundAmount > 0 ? Refund::STATUS_PENDING : Refund::STATUS_REJECTED; $reason = null; if ($refundAmount <= 0) { - if (! $eligible) { + if (!$eligible) { $reason = 'No refund due to late withdrawal.'; - } elseif (! empty($details['full_discount'])) { + } elseif (!empty($details['full_discount'])) { $reason = 'No refund due to full discount.'; } elseif ($debitAmount > 0) { $reason = 'No refund due; book fee balance remains.'; @@ -188,7 +189,7 @@ class RefundPolicyService 'updated_by' => $actorId, ]); - if (! $created) { + if (!$created) { return ['ok' => false, 'error' => 'Failed to create refund record.']; } diff --git a/app/Services/Refunds/RefundQueryService.php b/app/Services/Refunds/RefundQueryService.php index 1289e832..cf3fb261 100644 --- a/app/Services/Refunds/RefundQueryService.php +++ b/app/Services/Refunds/RefundQueryService.php @@ -16,7 +16,7 @@ class RefundQueryService $sortDir = strtolower((string) ($filters['sort_dir'] ?? 'desc')) === 'asc' ? 'asc' : 'desc'; $allowedSorts = ['created_at', 'updated_at', 'refund_amount', 'status', 'parent_id', 'invoice_id']; - if (! in_array($sortBy, $allowedSorts, true)) { + if (!in_array($sortBy, $allowedSorts, true)) { $sortBy = 'created_at'; } @@ -29,25 +29,25 @@ class RefundQueryService ->leftJoin('users as parents', 'parents.id', '=', 'refunds.parent_id') ->leftJoin('users as approvers', 'approvers.id', '=', 'refunds.approved_by'); - if (! empty($filters['status'])) { + if (!empty($filters['status'])) { $query->where('refunds.status', $filters['status']); } - if (! empty($filters['request'])) { + if (!empty($filters['request'])) { $query->where('refunds.request', $filters['request']); } - if (! empty($filters['parent_id'])) { + if (!empty($filters['parent_id'])) { $query->where('refunds.parent_id', (int) $filters['parent_id']); } - if (! empty($filters['invoice_id'])) { + if (!empty($filters['invoice_id'])) { $query->where('refunds.invoice_id', (int) $filters['invoice_id']); } - if (! empty($filters['school_year'])) { + if (!empty($filters['school_year'])) { $query->where('refunds.school_year', (string) $filters['school_year']); } - if (! empty($filters['semester'])) { + if (!empty($filters['semester'])) { $query->where('refunds.semester', (string) $filters['semester']); } - if (! empty($filters['q'])) { + if (!empty($filters['q'])) { $term = trim((string) $filters['q']); $query->where(function ($where) use ($term) { $where->where('refunds.reason', 'like', "%{$term}%") @@ -57,7 +57,7 @@ class RefundQueryService }); } - $paginator = $query->orderBy('refunds.'.$sortBy, $sortDir) + $paginator = $query->orderBy('refunds.' . $sortBy, $sortDir) ->paginate($perPage, ['*'], 'page', $page); return [ diff --git a/app/Services/Refunds/RefundRequestService.php b/app/Services/Refunds/RefundRequestService.php index aeb3aaad..fbc37bb9 100644 --- a/app/Services/Refunds/RefundRequestService.php +++ b/app/Services/Refunds/RefundRequestService.php @@ -18,7 +18,8 @@ class RefundRequestService private RefundSummaryService $summaryService, private RefundNotificationService $notifications, private ApplicationUrlService $urls, - ) {} + ) { + } public function requestRefund(array $payload, int $actorId): array { @@ -29,12 +30,12 @@ class RefundRequestService $paymentId = isset($payload['payment_id']) ? (int) $payload['payment_id'] : null; $reason = $payload['reason'] ?? null; - if (! in_array($requestType, self::REQUEST_TYPES, true)) { + if (!in_array($requestType, self::REQUEST_TYPES, true)) { return ['ok' => false, 'message' => 'Invalid refund request type.']; } $parent = User::query()->find($parentId); - if (! $parent) { + if (!$parent) { return ['ok' => false, 'message' => 'Parent not found.']; } @@ -100,19 +101,18 @@ class RefundRequestService 'status' => Refund::STATUS_PENDING, 'reason' => $reason, 'request' => $requestType, - 'note' => $paymentId ? ('duplicate-of-payment#'.$paymentId) : null, + 'note' => $paymentId ? ('duplicate-of-payment#' . $paymentId) : null, 'requested_at' => utc_now(), 'created_at' => utc_now(), 'updated_at' => utc_now(), 'updated_by' => $actorId, ]); - if (! $refund) { + if (!$refund) { Log::error('Failed to create refund request.', [ 'parent_id' => $parentId, 'type' => $requestType, ]); - return ['ok' => false, 'message' => 'Failed to create refund request.']; } diff --git a/app/Services/Reimbursements/ReimbursementBatchAssignmentService.php b/app/Services/Reimbursements/ReimbursementBatchAssignmentService.php index 29cbeec6..a56d19fb 100644 --- a/app/Services/Reimbursements/ReimbursementBatchAssignmentService.php +++ b/app/Services/Reimbursements/ReimbursementBatchAssignmentService.php @@ -9,7 +9,9 @@ use RuntimeException; class ReimbursementBatchAssignmentService { - public function __construct(private ReimbursementLookupService $lookupService) {} + public function __construct(private ReimbursementLookupService $lookupService) + { + } public function updateAssignment( int $expenseId, @@ -33,7 +35,7 @@ class ReimbursementBatchAssignmentService if ($batchId <= 0) { if ($activeItem) { $activeItem->update(['unassigned_at' => $now]); - if (! $reimbursementId && ! empty($activeItem->reimbursement_id)) { + if (!$reimbursementId && !empty($activeItem->reimbursement_id)) { $reimbursementId = (int) $activeItem->reimbursement_id; } } @@ -46,7 +48,7 @@ class ReimbursementBatchAssignmentService } $batch = ReimbursementBatch::query()->find($batchId); - if (! $batch || strtolower((string) $batch->status) !== ReimbursementBatch::STATUS_OPEN) { + if (!$batch || strtolower((string) $batch->status) !== ReimbursementBatch::STATUS_OPEN) { throw new RuntimeException('Batch not found or already closed.'); } @@ -61,7 +63,7 @@ class ReimbursementBatchAssignmentService } if ($activeSameBatch) { - if (! $reimbursementId) { + if (!$reimbursementId) { $reimbursementId = $activeItem->reimbursement_id ? (int) $activeItem->reimbursement_id : $this->lookupService->findReimbursementIdForExpense($expenseId); @@ -83,12 +85,12 @@ class ReimbursementBatchAssignmentService if ($activeItem) { $activeItem->update(['unassigned_at' => $now]); - if (! $reimbursementId && ! empty($activeItem->reimbursement_id)) { + if (!$reimbursementId && !empty($activeItem->reimbursement_id)) { $reimbursementId = (int) $activeItem->reimbursement_id; } } - if (! $reimbursementId) { + if (!$reimbursementId) { $reimbursementId = $this->lookupService->findReimbursementIdForExpense($expenseId); } @@ -103,7 +105,7 @@ class ReimbursementBatchAssignmentService 'semester' => $semester, ]); } catch (\Throwable $e) { - Log::error('Failed to assign expense to batch: '.$e->getMessage(), [ + Log::error('Failed to assign expense to batch: ' . $e->getMessage(), [ 'expense_id' => $expenseId, 'batch_id' => $batchId, ]); diff --git a/app/Services/Reimbursements/ReimbursementBatchService.php b/app/Services/Reimbursements/ReimbursementBatchService.php index 23829d16..698db538 100644 --- a/app/Services/Reimbursements/ReimbursementBatchService.php +++ b/app/Services/Reimbursements/ReimbursementBatchService.php @@ -12,7 +12,9 @@ use RuntimeException; class ReimbursementBatchService { - public function __construct(private ReimbursementLookupService $lookupService) {} + public function __construct(private ReimbursementLookupService $lookupService) + { + } public function createBatch(?string $title, int $userId, string $schoolYear, string $semester): array { @@ -29,7 +31,7 @@ class ReimbursementBatchService 'yearly_batch_number' => $sequence, ]); - $label = trim((string) $batch->title) !== '' ? (string) $batch->title : ('Batch #'.$sequence); + $label = trim((string) $batch->title) !== '' ? (string) $batch->title : ('Batch #' . $sequence); if (trim((string) $batch->title) === '') { $batch->title = $label; $batch->save(); @@ -45,7 +47,7 @@ class ReimbursementBatchService public function lockBatch(int $batchId, int $userId, string $schoolYear, string $semester): void { $batch = ReimbursementBatch::query()->find($batchId); - if (! $batch || strtolower((string) $batch->status) !== ReimbursementBatch::STATUS_OPEN) { + if (!$batch || strtolower((string) $batch->status) !== ReimbursementBatch::STATUS_OPEN) { throw new RuntimeException('Batch not found or already closed.'); } @@ -58,7 +60,7 @@ class ReimbursementBatchService $adminIds = array_values(array_unique($adminRows->pluck('admin_id')->map(fn ($id) => (int) $id)->all())); $requiredAdmins = array_values(array_filter($adminIds, static fn ($adminId) => $adminId > 0)); - if (! empty($requiredAdmins)) { + if (!empty($requiredAdmins)) { $uploadedAdminIds = ReimbursementBatchAdminFile::query() ->where('batch_id', $batchId) ->whereIn('admin_id', $requiredAdmins) @@ -69,7 +71,7 @@ class ReimbursementBatchService ->all(); foreach ($requiredAdmins as $adminId) { - if (! in_array($adminId, $uploadedAdminIds, true)) { + if (!in_array($adminId, $uploadedAdminIds, true)) { throw new RuntimeException('All admin sections must have a check file before submitting the batch.'); } } @@ -92,7 +94,7 @@ class ReimbursementBatchService $reimbId = $item->batch_reimb_id ?: ($item->expense_reimb_id ?: $this->lookupService->findReimbursementIdForExpense($expenseId)); - if (! $reimbId) { + if (!$reimbId) { $payload = [ 'expense_id' => $expenseId, 'amount' => (float) ($item->amount ?? 0), @@ -120,7 +122,7 @@ class ReimbursementBatchService ]); Expense::query()->where('id', $expenseId)->update(['reimbursement_id' => $reimbId]); - if (! empty($item->batch_item_id)) { + if (!empty($item->batch_item_id)) { ReimbursementBatchItem::query()->where('id', (int) $item->batch_item_id)->update([ 'reimbursement_id' => $reimbId, ]); diff --git a/app/Services/Reimbursements/ReimbursementDonationService.php b/app/Services/Reimbursements/ReimbursementDonationService.php index 26d25327..6413fee3 100644 --- a/app/Services/Reimbursements/ReimbursementDonationService.php +++ b/app/Services/Reimbursements/ReimbursementDonationService.php @@ -17,11 +17,11 @@ class ReimbursementDonationService } $expense = Expense::query()->find($expenseId); - if (! $expense) { + if (!$expense) { throw new RuntimeException('Expense not found.'); } - if (! empty($expense->reimbursement_id)) { + if (!empty($expense->reimbursement_id)) { throw new RuntimeException('Expense is already tied to a reimbursement.'); } @@ -46,7 +46,7 @@ class ReimbursementDonationService DB::commit(); } catch (\Throwable $e) { DB::rollBack(); - Log::error('Failed to mark donation: '.$e->getMessage(), ['expense_id' => $expenseId]); + Log::error('Failed to mark donation: ' . $e->getMessage(), ['expense_id' => $expenseId]); throw new RuntimeException('Unable to mark donation right now.'); } } diff --git a/app/Services/Reimbursements/ReimbursementEmailService.php b/app/Services/Reimbursements/ReimbursementEmailService.php index dd8ec02d..31adbcf6 100644 --- a/app/Services/Reimbursements/ReimbursementEmailService.php +++ b/app/Services/Reimbursements/ReimbursementEmailService.php @@ -11,7 +11,9 @@ use ZipArchive; class ReimbursementEmailService { - public function __construct(private ReimbursementRecipientService $recipients) {} + public function __construct(private ReimbursementRecipientService $recipients) + { + } public function sendBatchEmail( int $batchId, @@ -21,14 +23,14 @@ class ReimbursementEmailService array $checkIds ): bool { $batch = ReimbursementBatch::query()->find($batchId); - if (! $batch) { + if (!$batch) { throw new \RuntimeException('Requested batch was not found.'); } - $receiptRows = ! empty($receiptIds) ? $this->fetchBatchReceiptRows($batchId, $receiptIds) : []; + $receiptRows = !empty($receiptIds) ? $this->fetchBatchReceiptRows($batchId, $receiptIds) : []; $checkRows = []; - if (! empty($checkIds)) { + if (!empty($checkIds)) { $checkRows = ReimbursementBatchAdminFile::query() ->select('id as file_id', 'admin_id', 'filename', 'original_filename', 'uploaded_at') ->where('batch_id', $batchId) @@ -38,29 +40,29 @@ class ReimbursementEmailService $adminLookup = []; foreach ($this->recipients->adminRoster() as $admin) { - $adminLookup[(int) ($admin['id'] ?? 0)] = trim((string) (($admin['firstname'] ?? '').' '.($admin['lastname'] ?? ''))); + $adminLookup[(int) ($admin['id'] ?? 0)] = trim((string) (($admin['firstname'] ?? '') . ' ' . ($admin['lastname'] ?? ''))); } foreach ($checkRows as &$row) { $aid = (int) ($row['admin_id'] ?? 0); - $row['admin'] = $adminLookup[$aid] ?? ($aid > 0 ? 'Admin #'.$aid : 'Admin'); + $row['admin'] = $adminLookup[$aid] ?? ($aid > 0 ? 'Admin #' . $aid : 'Admin'); } unset($row); } $tempDir = storage_path('tmp'); - if (! is_dir($tempDir)) { + if (!is_dir($tempDir)) { mkdir($tempDir, 0755, true); } $cleanupPaths = []; - $batchLabel = trim((string) ($batch->title ?? '')) ?: ('Batch #'.((int) ($batch->yearly_batch_number ?? $batchId))); + $batchLabel = trim((string) ($batch->title ?? '')) ?: ('Batch #' . ((int) ($batch->yearly_batch_number ?? $batchId))); $batchFileLabel = $this->sanitizeAttachmentComponent($batchLabel); $csvPath = tempnam($tempDir, 'batch_csv_'); $cleanupPaths[] = $csvPath; $csvHandle = fopen($csvPath, 'w'); - if (! $csvHandle) { + if (!$csvHandle) { if (is_file($csvPath)) { @unlink($csvPath); } @@ -72,31 +74,31 @@ class ReimbursementEmailService $this->writeBatchCsvSummary($csvHandle, $receiptRows, $batchClosedDate); fclose($csvHandle); - $csvAttachmentName = $batchFileLabel.'_summary.csv'; + $csvAttachmentName = $batchFileLabel . '_summary.csv'; $receiptsArchivePath = null; $receiptZipCreated = false; - if (! empty($receiptRows)) { - $archivePath = $tempDir.'/batch_receipts_'.$batchId.'_'.date('Ymd_His').'_'.bin2hex(random_bytes(4)).'.zip'; - $zip = new ZipArchive; + if (!empty($receiptRows)) { + $archivePath = $tempDir . '/batch_receipts_' . $batchId . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.zip'; + $zip = new ZipArchive(); $added = 0; $usedNames = []; if ($zip->open($archivePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) { foreach ($receiptRows as $row) { - $sourcePath = storage_path('uploads/receipts/'.basename((string) ($row['receipt_filename'] ?? ''))); - if (! is_file($sourcePath)) { + $sourcePath = storage_path('uploads/receipts/' . basename((string) ($row['receipt_filename'] ?? ''))); + if (!is_file($sourcePath)) { continue; } $firstName = $row['purchaser_firstname'] ?? ''; - if (trim($firstName) === '' && ! empty($row['purchaser_lastname'] ?? '')) { + if (trim($firstName) === '' && !empty($row['purchaser_lastname'] ?? '')) { $firstName = $row['purchaser_lastname']; } $firstName = $this->sanitizeAttachmentComponent($firstName); $vendorPart = $this->sanitizeAttachmentComponent($row['retailor'] ?? ''); $datePart = $this->formatAttachmentDate($row['purchase_date'] ?? ''); $extension = pathinfo($sourcePath, PATHINFO_EXTENSION); - $extPart = $extension !== '' ? ('.'.strtolower($extension)) : ''; - $baseName = $firstName.'_'.$vendorPart.'_'.$datePart; + $extPart = $extension !== '' ? ('.' . strtolower($extension)) : ''; + $baseName = $firstName . '_' . $vendorPart . '_' . $datePart; $entryName = $this->uniqueZipEntryName($baseName, $extPart, $usedNames); if ($zip->addFile($sourcePath, $entryName)) { $added++; @@ -115,21 +117,21 @@ class ReimbursementEmailService $checksArchivePath = null; $checksAdded = 0; - if (! empty($checkRows)) { - $archivePath = $tempDir.'/batch_checks_'.$batchId.'_'.date('Ymd_His').'_'.bin2hex(random_bytes(4)).'.zip'; - $zip = new ZipArchive; + if (!empty($checkRows)) { + $archivePath = $tempDir . '/batch_checks_' . $batchId . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.zip'; + $zip = new ZipArchive(); $usedNames = []; if ($zip->open($archivePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) { foreach ($checkRows as $row) { - $sourcePath = storage_path('uploads/reimbursements/'.basename((string) ($row['filename'] ?? ''))); - if (! is_file($sourcePath)) { + $sourcePath = storage_path('uploads/reimbursements/' . basename((string) ($row['filename'] ?? ''))); + if (!is_file($sourcePath)) { continue; } $adminLabel = $row['admin'] ?? 'Admin'; $firstToken = strtok($adminLabel, ' '); $namePart = $this->sanitizeAttachmentComponent($firstToken ?: $adminLabel); $extension = pathinfo($sourcePath, PATHINFO_EXTENSION); - $extPart = $extension !== '' ? ('.'.strtolower($extension)) : ''; + $extPart = $extension !== '' ? ('.' . strtolower($extension)) : ''; $entryName = $this->uniqueZipEntryName($namePart, $extPart, $usedNames); if ($zip->addFile($sourcePath, $entryName)) { $checksAdded++; @@ -153,14 +155,14 @@ class ReimbursementEmailService $attachmentSummary[] = 'Check Scans'; } - $subject = 'Reimbursement Batch Export: '.$batchLabel; + $subject = 'Reimbursement Batch Export: ' . $batchLabel; $bodyParts = [ - '

Please find attached the export for '.htmlspecialchars($batchLabel, ENT_QUOTES, 'UTF-8').'.

', + '

Please find attached the export for ' . htmlspecialchars($batchLabel, ENT_QUOTES, 'UTF-8') . '.

', ]; if (trim($message) !== '') { - $bodyParts[] = '

Message:
'.nl2br(htmlspecialchars($message, ENT_QUOTES, 'UTF-8')).'

'; + $bodyParts[] = '

Message:
' . nl2br(htmlspecialchars($message, ENT_QUOTES, 'UTF-8')) . '

'; } - $bodyParts[] = '

Attachments: '.htmlspecialchars(implode(', ', $attachmentSummary), ENT_QUOTES, 'UTF-8').'.

'; + $bodyParts[] = '

Attachments: ' . htmlspecialchars(implode(', ', $attachmentSummary), ENT_QUOTES, 'UTF-8') . '.

'; $bodyParts[] = '

Regards,
Al Rahma Sunday School

'; $htmlBody = implode("\n", $bodyParts); @@ -168,10 +170,10 @@ class ReimbursementEmailService ['path' => $csvPath, 'name' => $csvAttachmentName], ]; if ($receiptsArchivePath) { - $attachments[] = ['path' => $receiptsArchivePath, 'name' => $batchFileLabel.'_receipts.zip']; + $attachments[] = ['path' => $receiptsArchivePath, 'name' => $batchFileLabel . '_receipts.zip']; } if ($checksArchivePath) { - $attachments[] = ['path' => $checksArchivePath, 'name' => $batchFileLabel.'_checks.zip']; + $attachments[] = ['path' => $checksArchivePath, 'name' => $batchFileLabel . '_checks.zip']; } $sender = $this->resolveSender('general'); @@ -179,11 +181,11 @@ class ReimbursementEmailService try { Mail::html($htmlBody, function ($message) use ($recipientEmail, $subject, $sender, $attachments) { $message->to($recipientEmail)->subject($subject); - if (! empty($sender['email'])) { + if (!empty($sender['email'])) { $message->from($sender['email'], $sender['name']); } foreach ($attachments as $file) { - if (! empty($file['path']) && is_file($file['path'])) { + if (!empty($file['path']) && is_file($file['path'])) { $message->attach($file['path'], ['as' => $file['name'] ?? basename($file['path'])]); } } @@ -191,8 +193,7 @@ class ReimbursementEmailService return true; } catch (\Throwable $e) { - Log::error('Failed to send batch export email: '.$e->getMessage()); - + Log::error('Failed to send batch export email: ' . $e->getMessage()); return false; } finally { foreach ($cleanupPaths as $path) { @@ -211,7 +212,7 @@ class ReimbursementEmailService ->leftJoin('users as u', 'u.id', '=', 'e.purchased_by') ->where('bi.batch_id', $batchId); - if (! empty($receiptIds)) { + if (!empty($receiptIds)) { $builder->whereIn('e.id', $receiptIds); } @@ -229,7 +230,7 @@ class ReimbursementEmailService 'purchaser_lastname' => $row->purchaser_lastname ?? null, ]; }, $rows), static function ($row) { - return ! empty($row['receipt_filename']); + return !empty($row['receipt_filename']); })); } @@ -246,7 +247,7 @@ class ReimbursementEmailService { $receiptTotalsByRecipient = []; foreach ($receiptRows as $row) { - $recipientName = trim(($row['purchaser_firstname'] ?? '').' '.($row['purchaser_lastname'] ?? '')); + $recipientName = trim(($row['purchaser_firstname'] ?? '') . ' ' . ($row['purchaser_lastname'] ?? '')); if ($recipientName === '') { $recipientName = 'Unknown'; } @@ -270,7 +271,7 @@ class ReimbursementEmailService implode(' | ', $descriptionParts), ]); } - if (! empty($receiptTotalsByRecipient)) { + if (!empty($receiptTotalsByRecipient)) { fputcsv($handle, []); fputcsv($handle, ['Totals by Recipient', '', '', '', '', '', '', '']); foreach ($receiptTotalsByRecipient as $recipient => $total) { @@ -293,46 +294,42 @@ class ReimbursementEmailService { $clean = preg_replace('/[^A-Za-z0-9]+/', '_', trim((string) $value)); $clean = trim($clean, '_'); - return $clean === '' ? 'unknown' : $clean; } private function formatAttachmentDate(?string $value): string { - if (! $value) { + if (!$value) { return 'unknown'; } $timestamp = strtotime($value); if ($timestamp === false) { return 'unknown'; } - return date('Ymd', $timestamp); } private function uniqueZipEntryName(string $base, string $extension, array &$used): string { - $candidate = $base.$extension; + $candidate = $base . $extension; $counter = 1; while (isset($used[$candidate])) { - $candidate = $base.'_'.$counter.$extension; + $candidate = $base . '_' . $counter . $extension; $counter++; } $used[$candidate] = true; - return $candidate; } private function formatCsvDate(?string $value): string { - if (! $value) { + if (!$value) { return ''; } $timestamp = strtotime($value); if ($timestamp === false) { return ''; } - return date('m-d-Y', $timestamp); } @@ -344,7 +341,6 @@ class ReimbursementEmailService if (is_array($senders) && isset($senders[$fromKey])) { $info = $senders[$fromKey]; - return [ 'name' => (string) ($info['name'] ?? 'Sender'), 'email' => (string) ($info['email'] ?? ''), diff --git a/app/Services/Reimbursements/ReimbursementExportService.php b/app/Services/Reimbursements/ReimbursementExportService.php index 7a297cc7..f2c4d8f6 100644 --- a/app/Services/Reimbursements/ReimbursementExportService.php +++ b/app/Services/Reimbursements/ReimbursementExportService.php @@ -8,7 +8,9 @@ use RuntimeException; class ReimbursementExportService { - public function __construct(private ReimbursementRecipientService $recipients) {} + public function __construct(private ReimbursementRecipientService $recipients) + { + } public function buildUnderProcessingCsv(): array { @@ -25,12 +27,12 @@ class ReimbursementExportService foreach ($records as $row) { $personId = (int) ($row->purchased_by ?? 0); - $name = trim(($row->purchaser_firstname ?? '').' '.($row->purchaser_lastname ?? '')); + $name = trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? '')); if ($name === '') { $name = $row->purchaser_firstname ?? $row->purchaser_lastname ?? 'Unknown'; } - $key = $personId > 0 ? 'id_'.$personId : 'name_'.strtolower($name); - if (! isset($grouped[$key])) { + $key = $personId > 0 ? 'id_' . $personId : 'name_' . strtolower($name); + if (!isset($grouped[$key])) { $grouped[$key] = [ 'name' => $name ?: 'Unknown', 'total' => 0.0, @@ -43,12 +45,12 @@ class ReimbursementExportService $grouped[$key]['total'] += $amount; $vendor = trim((string) ($row->retailor ?? '')); - if ($vendor !== '' && ! in_array($vendor, $grouped[$key]['vendors'], true)) { + if ($vendor !== '' && !in_array($vendor, $grouped[$key]['vendors'], true)) { $grouped[$key]['vendors'][] = $vendor; } $desc = trim((string) ($row->description ?? '')); - if ($desc !== '' && ! in_array($desc, $grouped[$key]['descriptions'], true)) { + if ($desc !== '' && !in_array($desc, $grouped[$key]['descriptions'], true)) { $grouped[$key]['descriptions'][] = $desc; } } @@ -76,16 +78,16 @@ class ReimbursementExportService ->select('reimbursements.*', 'u.firstname as reimb_firstname', 'u.lastname as reimb_lastname') ->leftJoin('users as u', 'u.id', '=', 'reimbursements.reimbursed_to'); - if (! empty($filters['semester'])) { + if (!empty($filters['semester'])) { $builder->where('reimbursements.semester', $filters['semester']); } - if (! empty($filters['status'])) { + if (!empty($filters['status'])) { $builder->where('reimbursements.status', $filters['status']); } - if (! empty($filters['user_id'])) { + if (!empty($filters['user_id'])) { $builder->where('reimbursements.reimbursed_to', $filters['user_id']); } - if (! empty($filters['school_year'])) { + if (!empty($filters['school_year'])) { $builder->where('reimbursements.school_year', $filters['school_year']); } @@ -94,8 +96,8 @@ class ReimbursementExportService $rows[] = ['Amount', 'Reimbursed To', 'Status', 'Method', 'Check #', 'School Year', 'Semester', 'Date']; foreach ($records as $row) { - $hasName = trim(($row->reimb_firstname ?? '').' '.($row->reimb_lastname ?? '')) !== ''; - if (! $hasName) { + $hasName = trim(($row->reimb_firstname ?? '') . ' ' . ($row->reimb_lastname ?? '')) !== ''; + if (!$hasName) { $label = $this->recipients->specialRecipientLabel($row->reimbursed_to ?? null); if ($label !== null) { $row->reimb_firstname = $label; @@ -105,7 +107,7 @@ class ReimbursementExportService $rows[] = [ $row->amount, - trim(($row->reimb_firstname ?? '').' '.($row->reimb_lastname ?? '')), + trim(($row->reimb_firstname ?? '') . ' ' . ($row->reimb_lastname ?? '')), $row->status, $row->reimbursement_method ?? '-', $row->check_number ?? '-', @@ -124,11 +126,11 @@ class ReimbursementExportService public function buildBatchCsv(int $batchId): array { $batch = ReimbursementBatch::query()->find($batchId); - if (! $batch) { + if (!$batch) { throw new RuntimeException('Batch not found.'); } - $batchLabel = trim((string) ($batch->title ?? '')) ?: ('Batch #'.$batchId); + $batchLabel = trim((string) ($batch->title ?? '')) ?: ('Batch #' . $batchId); $receiptRows = $this->fetchBatchReceiptRows($batchId); $rows = []; @@ -149,14 +151,14 @@ class ReimbursementExportService ->leftJoin('users as u', 'u.id', '=', 'e.purchased_by') ->where('bi.batch_id', $batchId); - if (! empty($receiptIds)) { + if (!empty($receiptIds)) { $builder->whereIn('e.id', $receiptIds); } $rows = $builder->get()->toArray(); return array_values(array_filter($rows, static function ($row) { - return ! empty($row->receipt_filename); + return !empty($row->receipt_filename); })); } @@ -173,7 +175,7 @@ class ReimbursementExportService { $receiptTotalsByRecipient = []; foreach ($receiptRows as $row) { - $recipientName = trim(($row->purchaser_firstname ?? '').' '.($row->purchaser_lastname ?? '')); + $recipientName = trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? '')); if ($recipientName === '') { $recipientName = 'Unknown'; } @@ -198,7 +200,7 @@ class ReimbursementExportService ]; } - if (! empty($receiptTotalsByRecipient)) { + if (!empty($receiptTotalsByRecipient)) { $rows[] = []; $rows[] = ['Totals by Recipient', '', '', '', '', '', '', '']; foreach ($receiptTotalsByRecipient as $recipient => $total) { @@ -219,14 +221,13 @@ class ReimbursementExportService private function formatCsvDate(?string $value): string { - if (! $value) { + if (!$value) { return ''; } $timestamp = strtotime($value); if ($timestamp === false) { return ''; } - return date('m-d-Y', $timestamp); } } diff --git a/app/Services/Reimbursements/ReimbursementFileService.php b/app/Services/Reimbursements/ReimbursementFileService.php index ec42d495..a842e351 100644 --- a/app/Services/Reimbursements/ReimbursementFileService.php +++ b/app/Services/Reimbursements/ReimbursementFileService.php @@ -12,7 +12,8 @@ class ReimbursementFileService { public function __construct( private ApplicationUrlService $urls - ) {} + ) { + } public function receiptUrl(?string $filename): ?string { @@ -31,7 +32,7 @@ class ReimbursementFileService public function storeReceipt(?UploadedFile $file): ?string { - if (! $file || ! $file->isValid()) { + if (!$file || !$file->isValid()) { return null; } @@ -41,10 +42,10 @@ class ReimbursementFileService $dir = $this->ensureUploadDir(); $extension = $file->getClientOriginalExtension(); - $extension = $extension !== '' ? '.'.strtolower($extension) : ''; - $filename = 'reimb_'.date('Ymd_His').'_'.Str::random(8).$extension; + $extension = $extension !== '' ? '.' . strtolower($extension) : ''; + $filename = 'reimb_' . date('Ymd_His') . '_' . Str::random(8) . $extension; - if (! $file->move($dir, $filename)) { + if (!$file->move($dir, $filename)) { throw new RuntimeException('Unable to save uploaded file.'); } @@ -55,10 +56,10 @@ class ReimbursementFileService { $dir = $this->ensureUploadDir(); $extension = $file->getClientOriginalExtension(); - $extension = $extension !== '' ? '.'.strtolower($extension) : ''; - $filename = 'batch_check_'.date('Ymd_His').'_'.Str::random(8).$extension; + $extension = $extension !== '' ? '.' . strtolower($extension) : ''; + $filename = 'batch_check_' . date('Ymd_His') . '_' . Str::random(8) . $extension; - if (! $file->move($dir, $filename)) { + if (!$file->move($dir, $filename)) { throw new RuntimeException('Unable to save uploaded file.'); } @@ -67,8 +68,8 @@ class ReimbursementFileService ->where('admin_id', $adminId) ->first(); - if ($existing && ! empty($existing->filename)) { - $oldPath = $dir.DIRECTORY_SEPARATOR.$existing->filename; + if ($existing && !empty($existing->filename)) { + $oldPath = $dir . DIRECTORY_SEPARATOR . $existing->filename; if (is_file($oldPath)) { @unlink($oldPath); } @@ -101,13 +102,13 @@ class ReimbursementFileService { $dir = storage_path('uploads/reimbursements'); - if (! is_dir($dir)) { - if (! @mkdir($dir, 0755, true) && ! is_dir($dir)) { + if (!is_dir($dir)) { + if (!@mkdir($dir, 0755, true) && !is_dir($dir)) { throw new RuntimeException('Upload directory is not available.'); } } - if (! is_writable($dir)) { + if (!is_writable($dir)) { throw new RuntimeException('Upload directory is not writable.'); } diff --git a/app/Services/Reimbursements/ReimbursementQueryService.php b/app/Services/Reimbursements/ReimbursementQueryService.php index 9d65a734..66b2d40f 100644 --- a/app/Services/Reimbursements/ReimbursementQueryService.php +++ b/app/Services/Reimbursements/ReimbursementQueryService.php @@ -11,7 +11,8 @@ class ReimbursementQueryService public function __construct( private ReimbursementRecipientService $recipients, private ReimbursementFileService $files - ) {} + ) { + } public function underProcessing(): array { @@ -44,7 +45,7 @@ class ReimbursementQueryService } $receiptUrl = $this->files->expenseReceiptUrl($row->expense_receipt ?? null); - $fullName = trim(($row->purchaser_firstname ?? '').' '.($row->purchaser_lastname ?? '')) ?: 'Unknown'; + $fullName = trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? '')) ?: 'Unknown'; $item = [ 'id' => $expenseId, @@ -95,16 +96,16 @@ class ReimbursementQueryService } $receiptUrl = $this->files->expenseReceiptUrl($row->expense_receipt ?? null); - $purchaser = trim(($row->purchaser_firstname ?? '').' '.($row->purchaser_lastname ?? '')) ?: 'Unknown'; + $purchaser = trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? '')) ?: 'Unknown'; $yearlyNumber = (int) ($row->batch_year_number ?? 0); $batchLabel = trim((string) ($row->batch_title ?? '')); if ($batchLabel === '') { $fallbackNumber = $yearlyNumber > 0 ? $yearlyNumber : $batchId; - $batchLabel = 'Batch #'.$fallbackNumber; + $batchLabel = 'Batch #' . $fallbackNumber; } $adminId = $row->admin_id ? (int) $row->admin_id : 0; $adminName = $adminId > 0 - ? (trim(($row->admin_firstname ?? '').' '.($row->admin_lastname ?? '')) ?: 'Admin') + ? (trim(($row->admin_firstname ?? '') . ' ' . ($row->admin_lastname ?? '')) ?: 'Admin') : 'Unassigned'; $batchStatus = strtolower(trim((string) ($row->batch_status ?? ''))) ?: 'open'; @@ -126,7 +127,7 @@ class ReimbursementQueryService $itemsMap[$expenseId] = $item; - if (! isset($batchStructures[$batchId])) { + if (!isset($batchStructures[$batchId])) { $batchStructures[$batchId] = [ 'batchId' => $batchId, 'label' => $batchLabel, @@ -142,7 +143,7 @@ class ReimbursementQueryService } $slotKey = $adminId ?: 0; - if (! isset($batchStructures[$batchId]['slots'][$slotKey])) { + if (!isset($batchStructures[$batchId]['slots'][$slotKey])) { $batchStructures[$batchId]['slots'][$slotKey] = [ 'admin_id' => $adminId ?: 0, 'admin_name' => $adminId > 0 ? $adminName : 'Unassigned', @@ -154,7 +155,7 @@ class ReimbursementQueryService } $adminFileMap = []; - if (! empty($batchStructures)) { + if (!empty($batchStructures)) { $batchIds = array_keys($batchStructures); $files = ReimbursementBatchAdminFile::query() ->select('batch_id', 'admin_id', 'filename', 'original_filename') @@ -187,7 +188,6 @@ class ReimbursementQueryService $existingBatches = array_map(static function (array $batch) { $normalizedSlots = array_map(static function (array $slot) { $slot['items'] = array_values(array_map('intval', $slot['items'])); - return $slot; }, array_values($batch['slots'])); @@ -238,13 +238,13 @@ class ReimbursementQueryService ->where('b.status', 'closed') ->whereNull('bi.unassigned_at'); - if (! empty($filters['school_year'])) { + if (!empty($filters['school_year'])) { $batchQuery->where(function ($q) use ($filters) { $q->where('b.school_year', $filters['school_year']) ->orWhere('e.school_year', $filters['school_year']); }); } - if (! empty($filters['user_id'])) { + if (!empty($filters['user_id'])) { $batchQuery->where('e.purchased_by', $filters['user_id']); } @@ -255,10 +255,10 @@ class ReimbursementQueryService continue; } $labelNumber = (int) ($row->yearly_batch_number ?? $bid); - if (! isset($batchSummaries[$bid])) { + if (!isset($batchSummaries[$bid])) { $batchSummaries[$bid] = [ 'batch_id' => $bid, - 'title' => trim((string) ($row->batch_title ?? '')) ?: ('Batch #'.$labelNumber), + 'title' => trim((string) ($row->batch_title ?? '')) ?: ('Batch #' . $labelNumber), 'sequence' => $labelNumber, 'closed_at' => $row->closed_at ?? null, 'amount' => 0.0, @@ -269,7 +269,7 @@ class ReimbursementQueryService $batchSummaries[$bid]['amount'] += (float) $amount; $batchSummaries[$bid]['items'] += 1; - if (! isset($batchDetails[$bid])) { + if (!isset($batchDetails[$bid])) { $batchDetails[$bid] = [ 'title' => $batchSummaries[$bid]['title'], 'sequence' => $labelNumber, @@ -278,7 +278,7 @@ class ReimbursementQueryService 'checks' => [], ]; } - if (! isset($batchAttachments[$bid])) { + if (!isset($batchAttachments[$bid])) { $batchAttachments[$bid] = [ 'receipts' => [], 'checks' => [], @@ -289,7 +289,7 @@ class ReimbursementQueryService 'amount' => (float) $amount, 'description' => $row->description ?? '', 'vendor' => $row->retailor ?? '', - 'purchased_by' => trim(($row->purchaser_firstname ?? '').' '.($row->purchaser_lastname ?? '')), + 'purchased_by' => trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? '')), 'receipt_url' => $this->files->expenseReceiptUrl($row->expense_receipt ?? null), ]; @@ -309,7 +309,7 @@ class ReimbursementQueryService } } - if (! empty($batchSummaries)) { + if (!empty($batchSummaries)) { $batchIds = array_keys($batchSummaries); $files = ReimbursementBatchAdminFile::query() ->select('id as file_id', 'batch_id', 'admin_id', 'filename', 'original_filename', 'uploaded_at') @@ -319,22 +319,22 @@ class ReimbursementQueryService $adminNames = $this->recipients->adminRoster(); $adminNameMap = []; foreach ($adminNames as $admin) { - $adminNameMap[(int) $admin['id']] = trim(($admin['firstname'] ?? '').' '.($admin['lastname'] ?? '')); + $adminNameMap[(int) $admin['id']] = trim(($admin['firstname'] ?? '') . ' ' . ($admin['lastname'] ?? '')); } foreach ($files as $file) { $bid = (int) ($file->batch_id ?? 0); - if ($bid <= 0 || ! isset($batchDetails[$bid])) { + if ($bid <= 0 || !isset($batchDetails[$bid])) { continue; } $aid = (int) ($file->admin_id ?? 0); $batchDetails[$bid]['checks'][] = [ - 'admin' => $adminNameMap[$aid] ?? ($aid > 0 ? 'Admin #'.$aid : 'Unassigned'), + 'admin' => $adminNameMap[$aid] ?? ($aid > 0 ? 'Admin #' . $aid : 'Unassigned'), 'filename' => $file->filename, 'original' => $file->original_filename ?? $file->filename, 'url' => $this->files->adminFileUrl($file->filename ?? '', 'inline'), ]; - if (! isset($batchAttachments[$bid])) { + if (!isset($batchAttachments[$bid])) { $batchAttachments[$bid] = [ 'receipts' => [], 'checks' => [], @@ -344,19 +344,18 @@ class ReimbursementQueryService 'file_id' => (int) ($file->file_id ?? 0), 'filename' => $file->filename, 'original_filename' => $file->original_filename ?? $file->filename, - 'admin' => $adminNameMap[$aid] ?? ($aid > 0 ? 'Admin #'.$aid : 'Unassigned'), + 'admin' => $adminNameMap[$aid] ?? ($aid > 0 ? 'Admin #' . $aid : 'Unassigned'), 'url' => $this->files->adminFileUrl($file->filename ?? '', 'inline'), 'uploaded_at' => $file->uploaded_at ?? null, ]; } } - if (! empty($batchSummaries)) { + if (!empty($batchSummaries)) { $batchSummaries = array_values($batchSummaries); usort($batchSummaries, static function ($a, $b) { $aSeq = (int) ($a['sequence'] ?? 0); $bSeq = (int) ($b['sequence'] ?? 0); - return $bSeq <=> $aSeq; }); } @@ -372,16 +371,16 @@ class ReimbursementQueryService ->leftJoin('users as u', 'u.id', '=', 'e.purchased_by') ->where('e.category', 'Donation'); - if (! empty($filters['school_year'])) { + if (!empty($filters['school_year'])) { $donationQuery->where('e.school_year', $filters['school_year']); } - if (! empty($filters['semester'])) { + if (!empty($filters['semester'])) { $donationQuery->where('e.semester', $filters['semester']); } - if (! empty($filters['user_id'])) { + if (!empty($filters['user_id'])) { $donationQuery->where('e.purchased_by', $filters['user_id']); } - if (! empty($filters['status'])) { + if (!empty($filters['status'])) { $donationQuery->where(function ($q) use ($filters) { $q->where('e.status', $filters['status']) ->orWhere('e.status', strtolower((string) $filters['status'])) @@ -395,7 +394,7 @@ class ReimbursementQueryService foreach ($donationRows as $row) { $amount = (float) ($row->expense_amount ?? 0); $donationTotal += $amount; - $purchaser = trim(($row->purchaser_firstname ?? '').' '.($row->purchaser_lastname ?? '')); + $purchaser = trim(($row->purchaser_firstname ?? '') . ' ' . ($row->purchaser_lastname ?? '')); if ($purchaser === '') { $purchaser = 'Unknown'; } @@ -429,8 +428,8 @@ class ReimbursementQueryService } $recipientId = $e['reimb_recipient_id'] ?? ($e['reimbursed_to'] ?? null); - $hasName = trim(($e['reimb_firstname'] ?? '').' '.($e['reimb_lastname'] ?? '')) !== ''; - if (! $hasName) { + $hasName = trim(($e['reimb_firstname'] ?? '') . ' ' . ($e['reimb_lastname'] ?? '')) !== ''; + if (!$hasName) { $label = $this->recipients->specialRecipientLabel($recipientId); if ($label !== null) { $e['reimb_firstname'] = $label; diff --git a/app/Services/Reimbursements/ReimbursementRecipientService.php b/app/Services/Reimbursements/ReimbursementRecipientService.php index eeef0bed..d614b514 100644 --- a/app/Services/Reimbursements/ReimbursementRecipientService.php +++ b/app/Services/Reimbursements/ReimbursementRecipientService.php @@ -29,7 +29,7 @@ class ReimbursementRecipientService if ($id <= 0 || in_array($roleName, $excludedRoles, true)) { continue; } - if (! isset($staff[$id])) { + if (!isset($staff[$id])) { $staff[$id] = [ 'id' => $id, 'firstname' => $row->firstname ?? '', @@ -39,9 +39,8 @@ class ReimbursementRecipientService } uasort($staff, static function (array $a, array $b) { - $nameA = trim(($a['firstname'] ?? '').' '.($a['lastname'] ?? '')); - $nameB = trim(($b['firstname'] ?? '').' '.($b['lastname'] ?? '')); - + $nameA = trim(($a['firstname'] ?? '') . ' ' . ($a['lastname'] ?? '')); + $nameB = trim(($b['firstname'] ?? '') . ' ' . ($b['lastname'] ?? '')); return strcasecmp($nameA, $nameB); }); @@ -56,7 +55,7 @@ class ReimbursementRecipientService public function adminRoster(): array { $admins = $this->staffUsers(); - if (! empty($admins)) { + if (!empty($admins)) { return $admins; } @@ -65,12 +64,11 @@ class ReimbursementRecipientService public function specialRecipientLabel($value): ?string { - if ($value === null || ! is_numeric($value)) { + if ($value === null || !is_numeric($value)) { return null; } $id = (int) $value; - return self::SPECIAL_RECIPIENTS[$id] ?? null; } @@ -81,7 +79,7 @@ class ReimbursementRecipientService }, $users); foreach (self::SPECIAL_RECIPIENTS as $id => $label) { - if (! in_array($id, $existingIds, true)) { + if (!in_array($id, $existingIds, true)) { $users[] = [ 'id' => $id, 'firstname' => $label, diff --git a/app/Services/Reports/ReportCards/ReportCardService.php b/app/Services/Reports/ReportCards/ReportCardService.php index 2ecc82db..b2098603 100644 --- a/app/Services/Reports/ReportCards/ReportCardService.php +++ b/app/Services/Reports/ReportCards/ReportCardService.php @@ -2,9 +2,10 @@ namespace App\Services\Reports\ReportCards; +use App\Models\Calendar; use App\Models\AttendanceData; use App\Models\AttendanceRecord; -use App\Models\Calendar; +use App\Models\ClassSection; use App\Models\Configuration; use App\Models\ReportCardAcknowledgement; use App\Models\ScoreComment; @@ -12,12 +13,13 @@ use App\Models\SemesterScore; use App\Models\Student; use App\Models\StudentClass; use App\Models\TeacherClass; +use App\Models\User; +use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\DB; class ReportCardService { private string $schoolYear; - private string $semester; public function __construct() @@ -54,7 +56,7 @@ class ReportCardService ->get(); foreach ($q2->all() as $r) { $val = (string) ($r->school_year ?? ''); - if ($val !== '' && ! in_array($val, $schoolYears, true)) { + if ($val !== '' && !in_array($val, $schoolYears, true)) { $schoolYears[] = $val; } } @@ -82,7 +84,7 @@ class ReportCardService ->get(); foreach ($rs2->all() as $r) { $val = (string) ($r->semester ?? ''); - if ($val !== '' && ! in_array($val, $semesters, true)) { + if ($val !== '' && !in_array($val, $semesters, true)) { $semesters[] = $val; } } @@ -91,14 +93,14 @@ class ReportCardService $defaults = array_values(array_filter([(string) ($this->semester ?? ''), 'Fall', 'Spring'], static fn ($v) => $v !== '')); foreach ($defaults as $d) { - if (! in_array($d, $semesters, true)) { + if (!in_array($d, $semesters, true)) { $semesters[] = $d; } } $semesters = array_values(array_unique($semesters)); - if ($sem === '' && ! empty($semesters)) { + if ($sem === '' && !empty($semesters)) { $sem = $semesters[0]; - } elseif ($sem !== '' && ! in_array($sem, $semesters, true)) { + } elseif ($sem !== '' && !in_array($sem, $semesters, true)) { array_unshift($semesters, $sem); $semesters = array_values(array_unique($semesters)); } @@ -126,7 +128,7 @@ class ReportCardService ->get() ->map(fn ($r) => (array) $r) ->all(); - if (! empty($stuRows)) { + if (!empty($stuRows)) { $students = $stuRows; } } catch (\Throwable $e) { @@ -252,7 +254,7 @@ class ReportCardService $students = $this->fetchStudentsByClass($sectionId, $year); } $rosterSemester = ''; - $usedFallback = ! empty($students); + $usedFallback = !empty($students); } if (empty($students)) { @@ -299,7 +301,7 @@ class ReportCardService $scoreByStudent = []; foreach ($scoreRows as $row) { $sid = (int) ($row['student_id'] ?? 0); - if ($sid > 0 && ! isset($scoreByStudent[$sid])) { + if ($sid > 0 && !isset($scoreByStudent[$sid])) { $scoreByStudent[$sid] = $row; } } @@ -324,7 +326,7 @@ class ReportCardService ->all(); foreach ($otherRows as $row) { $sid = (int) ($row['student_id'] ?? 0); - if ($sid > 0 && ! isset($firstScoreByStudent[$sid])) { + if ($sid > 0 && !isset($firstScoreByStudent[$sid])) { $firstScoreByStudent[$sid] = $row; } } @@ -387,7 +389,7 @@ class ReportCardService ->all(); foreach ($ackRows as $row) { $sid = (int) ($row['student_id'] ?? 0); - if ($sid > 0 && ! isset($ackMap[$sid])) { + if ($sid > 0 && !isset($ackMap[$sid])) { $ackMap[$sid] = $row; } } @@ -400,7 +402,7 @@ class ReportCardService $warningCount = 0; foreach ($students as $student) { $sid = (int) ($student['id'] ?? 0); - $name = trim(((string) ($student['firstname'] ?? '')).' '.((string) ($student['lastname'] ?? ''))); + $name = trim(((string) ($student['firstname'] ?? '')) . ' ' . ((string) ($student['lastname'] ?? ''))); $missing = []; $warnings = []; @@ -415,7 +417,7 @@ class ReportCardService $semesterScore = null; $hasAllComponents = false; - if (! $score) { + if (!$score) { $missing[] = 'Score record'; } else { $attendanceScore = $score['attendance_score'] ?? null; @@ -428,11 +430,11 @@ class ReportCardService $score['project_avg'] ?? null, $score['test_avg'] ?? null, ]; - $hasAllComponents = ! in_array(false, array_map($isNumeric, $components), true); + $hasAllComponents = !in_array(false, array_map($isNumeric, $components), true); if ($isSecond) { $examScore = $score['final_exam_score'] ?? null; - if (! $isNumeric($examScore) && $isNumeric($score['midterm_exam_score'] ?? null)) { + if (!$isNumeric($examScore) && $isNumeric($score['midterm_exam_score'] ?? null)) { $examScore = $score['midterm_exam_score']; $warnings[] = 'Final exam stored as midterm'; } @@ -442,13 +444,13 @@ class ReportCardService $examScore = $score['final_exam_score'] ?? ($score['midterm_exam_score'] ?? null); } - if (! $isNumeric($examScore)) { + if (!$isNumeric($examScore)) { $missing[] = $isSecond ? 'Final exam score' : ($isFirst ? 'Midterm exam score' : 'Exam score'); } - if (! $isNumeric($attendanceScore)) { + if (!$isNumeric($attendanceScore)) { $missing[] = 'Attendance score'; } - if (! $isNumeric($ptapScore)) { + if (!$isNumeric($ptapScore)) { if ($hasAllComponents) { $warnings[] = 'PTAP computed from components'; } else { @@ -457,7 +459,7 @@ class ReportCardService } $canComputeSemester = $isNumeric($examScore) && $isNumeric($attendanceScore) && ($isNumeric($ptapScore) || $hasAllComponents); - if (! $isNumeric($semesterScore)) { + if (!$isNumeric($semesterScore)) { if ($canComputeSemester) { $warnings[] = 'Semester score computed'; } else { @@ -467,7 +469,7 @@ class ReportCardService if ($isSecond) { $firstScore = $firstScoreByStudent[$sid]['semester_score'] ?? null; - if (! $isNumeric($firstScore)) { + if (!$isNumeric($firstScore)) { $missing[] = 'First semester score'; } } @@ -480,7 +482,7 @@ class ReportCardService ? ($commentSet[$commentKey] ?? '') : ($commentSet['final'] ?? ($commentSet['midterm'] ?? '')); if (trim((string) $examComment) === '') { - $missing[] = $commentLabel.' comment'; + $missing[] = $commentLabel . ' comment'; } if (trim((string) ($commentSet['ptap'] ?? '')) === '') { $missing[] = 'PTAP comment'; @@ -493,7 +495,7 @@ class ReportCardService if ($isComplete) { $completeCount++; } - if (! empty($warnings)) { + if (!empty($warnings)) { $warningCount++; } @@ -562,7 +564,7 @@ class ReportCardService $reportDate = $this->sanitizeReportDate((string) ($params['report_date'] ?? '')); $data = $this->prepareStudentReportData($studentId, $schoolYear, $semester); - if (! $data) { + if (!$data) { return ['ok' => false, 'message' => 'Student not found or missing scores.']; } @@ -572,7 +574,7 @@ class ReportCardService $pdf = new \FPDF('P', 'mm', 'Letter'); $this->formatReportPDF($pdf, $data); - $filename = 'ReportCard_'.($data['student']['lastname'] ?? 'student').'.pdf'; + $filename = 'ReportCard_' . ($data['student']['lastname'] ?? 'student') . '.pdf'; $pdfContent = $pdf->Output('S'); @@ -594,10 +596,10 @@ class ReportCardService ->join('students as s', 's.id', '=', 'semester_scores.student_id') ->where('s.is_active', 1) ->where('semester_scores.class_section_id', $classSectionId); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $q->where('semester_scores.school_year', $schoolYear); } - if (! empty($semester)) { + if (!empty($semester)) { $this->applySemesterFilter($q, $semester, 'semester_scores.semester'); } $scores = $q @@ -607,7 +609,7 @@ class ReportCardService ->map(fn ($r) => $r->toArray()) ->all(); - if (! $scores) { + if (!$scores) { return ['ok' => false, 'message' => 'No students found for this class section.']; } @@ -623,7 +625,7 @@ class ReportCardService } } - $filename = 'ClassReport_Section_'.$classSectionId.'.pdf'; + $filename = 'ClassReport_Section_' . $classSectionId . '.pdf'; $pdfContent = $pdf->Output('S'); return [ @@ -665,7 +667,7 @@ class ReportCardService ->orderBy('s.firstname', 'ASC') ->orderBy('s.lastname', 'ASC'); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $query->where('student_class.school_year', $schoolYear); } @@ -681,7 +683,6 @@ class ReportCardService if ($s === 'spring' || $s === 'second' || str_contains($s, 'spring') || str_contains($s, '2')) { return 'spring'; } - return ''; } @@ -708,7 +709,7 @@ class ReportCardService private function applySemesterFilter($builder, ?string $semester, string $field = 'semester'): void { $vals = $this->semesterVariants($semester); - if (! empty($vals)) { + if (!empty($vals)) { $builder->whereIn($field, $vals); } } @@ -716,7 +717,7 @@ class ReportCardService private function applySemesterExclusion($builder, ?string $semester, string $field = 'semester'): void { $vals = $this->semesterVariants($semester); - if (! empty($vals)) { + if (!empty($vals)) { $builder->whereNotIn($field, $vals); } } @@ -760,7 +761,6 @@ class ReportCardService if ($weekday === 0) { return $now->format('Y-m-d'); } - return $now->modify('next sunday')->format('Y-m-d'); } @@ -788,14 +788,13 @@ class ReportCardService $sundays[] = $cursor->format('Y-m-d'); $cursor = $cursor->modify('+7 days'); } - return $sundays; } private function prepareStudentReportData(int $studentId, ?string $schoolYear = null, ?string $semester = null) { $student = Student::query()->find($studentId); - if (! $student || (int) ($student->is_active ?? 1) !== 1) { + if (!$student || (int) ($student->is_active ?? 1) !== 1) { return null; } @@ -816,7 +815,7 @@ class ReportCardService $this->applySemesterFilter($qb, $refSemester, 'semester'); } $score = $qb->orderBy('updated_at', 'DESC')->orderBy('id', 'DESC')->first(); - if (! $score) { + if (!$score) { return null; } $score = $score->toArray(); @@ -846,7 +845,7 @@ class ReportCardService } } - if (! $sectionId || $sectionCode <= 0) { + if (!$sectionId || $sectionCode <= 0) { try { $scRow = DB::table('student_class') ->select('class_section_id') @@ -855,7 +854,7 @@ class ReportCardService ->orderByRaw('COALESCE(updated_at, created_at) DESC') ->limit(1) ->first(); - if (! empty($scRow->class_section_id)) { + if (!empty($scRow->class_section_id)) { $sectionCode = (int) $scRow->class_section_id; $row = DB::table('classSection') ->select('id') @@ -888,7 +887,7 @@ class ReportCardService if (empty($taNames)) { $taNames = $names['ta_names']; } - if (empty($teacherNamesList) && ! empty($names['teacher_names'])) { + if (empty($teacherNamesList) && !empty($names['teacher_names'])) { $teacherNamesList = $names['teacher_names']; } } @@ -916,22 +915,22 @@ class ReportCardService if ($commentVal === '') { continue; } - if (! isset($commentMap[$typeRaw])) { + if (!isset($commentMap[$typeRaw])) { $commentMap[$typeRaw] = $commentVal; } } - if (isset($commentMap['attendance']) && ! isset($score['attendance_comment'])) { + if (isset($commentMap['attendance']) && !isset($score['attendance_comment'])) { $score['attendance_comment'] = $commentMap['attendance']; } $att = $score['attendance_score'] ?? null; $attendanceCommentVal = $commentMap['attendance'] ?? $score['attendance_comment'] ?? null; - if ((! is_string($attendanceCommentVal) || trim($attendanceCommentVal) === '') && is_numeric($att) && function_exists('attendance_comment_from_score')) { + if ((!is_string($attendanceCommentVal) || trim($attendanceCommentVal) === '') && is_numeric($att) && function_exists('attendance_comment_from_score')) { $autoAttendance = attendance_comment_from_score((float) $att, (string) ($student->firstname ?? '')); if (is_string($autoAttendance) && $autoAttendance !== '') { $commentMap['attendance'] = $autoAttendance; - if (! isset($score['attendance_comment'])) { + if (!isset($score['attendance_comment'])) { $score['attendance_comment'] = $autoAttendance; } } @@ -943,7 +942,7 @@ class ReportCardService if ($normSemester !== '') { $events = Calendar::getEventsBySchoolYearAndSemester($refYear, $normSemester); $dates = array_values(array_filter(array_map(static fn ($r) => (string) ($r['date'] ?? ''), $events))); - if (! empty($dates)) { + if (!empty($dates)) { $start = min($dates); $end = max($dates); $sundays = $this->listSundays($start, $end); @@ -968,7 +967,7 @@ class ReportCardService static fn ($r) => isset($r['total_attendance']) ? (int) $r['total_attendance'] : null, $attRows ), static fn ($v) => $v !== null)); - if (! empty($vals)) { + if (!empty($vals)) { $totalSemesterDays = max($vals); } } catch (\Throwable $e) { @@ -1025,8 +1024,7 @@ class ReportCardService $withPrefix = static function (array $row): string { $first = trim((string) ($row['firstname'] ?? '')); $last = trim((string) ($row['lastname'] ?? '')); - $name = trim($last.', '.$first, ' ,'); - + $name = trim($last . ', ' . $first, ' ,'); return $name !== '' ? $name : 'N/A'; }; $normalizePos = static function (?string $pos): string { @@ -1034,7 +1032,6 @@ class ReportCardService if ($pos === 'ta' || $pos === 'assistant') { return 'ta'; } - return 'main'; }; @@ -1068,7 +1065,7 @@ class ReportCardService $ids = [$sectionIdOrCode]; $rows = $runner($ids, (string) $schoolYear, (string) $semester); - if (! empty($rows)) { + if (!empty($rows)) { $consume($rows); } @@ -1123,7 +1120,6 @@ class ReportCardService if (is_numeric($val)) { return number_format((float) $val, 1); } - return (string) $val; }; $splitText = static function ($text, int $limit = 55): array { @@ -1133,7 +1129,6 @@ class ReportCardService } $lines = explode("\n", wordwrap($text, $limit)); $lines[] = ''; - return $lines; }; $drawLabeledCell = static function (\FPDF $pdf, string $label, string $value, float $width = 95) { @@ -1148,7 +1143,6 @@ class ReportCardService return $item; } } - return null; }; $wrapLinesToWidth = static function (\FPDF $pdf, string $text, float $width) { @@ -1159,19 +1153,18 @@ class ReportCardService if ($width <= 0) { return [$text]; } - $segments = preg_split('/\\r?\\n+/', $text); + $segments = preg_split("/\\r?\\n+/", $text); $lines = []; foreach ($segments as $seg) { $seg = trim($seg); if ($seg === '') { $lines[] = ' '; - continue; } $words = preg_split('/\\s+/u', $seg); $current = ''; foreach ($words as $word) { - $trial = trim($current === '' ? $word : ($current.' '.$word)); + $trial = trim($current === '' ? $word : ($current . ' ' . $word)); if ($pdf->GetStringWidth($trial) <= $width) { $current = $trial; } else { @@ -1185,7 +1178,6 @@ class ReportCardService $lines[] = $current; } } - return $lines; }; $draw3ColumnRow = static function (\FPDF $pdf, string $label, $score, $feedback) use ($wrapLinesToWidth) { @@ -1243,13 +1235,12 @@ class ReportCardService $seg = trim($seg); if ($seg === '') { $out[] = ' '; - continue; } $words = preg_split('/\\s+/u', $seg); $current = ''; foreach ($words as $word) { - $trial = $current === '' ? $word : ($current.' '.$word); + $trial = $current === '' ? $word : ($current . ' ' . $word); if ($pdf->GetStringWidth($trial) <= ($width - 2)) { $current = $trial; } else { @@ -1263,15 +1254,14 @@ class ReportCardService $out[] = $current; } } - - return ! empty($out) ? $out : [' ']; + return !empty($out) ? $out : [' ']; }; if ($startY !== null) { $pdf->SetY($startY); } foreach ($rows as $row) { - if (! is_array($row) || count($row) < 4) { + if (!is_array($row) || count($row) < 4) { continue; } [$labelLeft, $valueLeft, $labelRight, $valueRight] = $row; @@ -1326,7 +1316,6 @@ class ReportCardService $currentY += $rowHeight; $pdf->SetY($currentY); } - return $currentY; }; @@ -1343,7 +1332,7 @@ class ReportCardService } $teacherNamesList = $data['teacher_names'] ?? []; - if (empty($teacherNamesList) && ! empty($data['teacher_name'])) { + if (empty($teacherNamesList) && !empty($data['teacher_name'])) { $teacherNamesList = [trim((string) $data['teacher_name'])]; } $teacherNamesList = array_values(array_filter( @@ -1376,9 +1365,9 @@ class ReportCardService $schoolYear = (string) ($data['score']['school_year'] ?? ($data['score']['year'] ?? 'N/A')); if (preg_match('/^(\\d{4})-(\\d{4})$/', $schoolYear, $m)) { - $schoolYear = $m[1].'/'.$m[2]; + $schoolYear = $m[1] . '/' . $m[2]; } - $studentName = trim(($data['student']['firstname'] ?? '').' '.($data['student']['lastname'] ?? '')); + $studentName = trim(($data['student']['firstname'] ?? '') . ' ' . ($data['student']['lastname'] ?? '')); $gradeLabel = (string) ($data['grade'] ?? ($data['class_section_name'] ?? 'N/A')); $today = (string) ($data['report_date_display'] ?? date('m-d-Y')); $firstSemScore = $data['first_semester_score'] ?? null; @@ -1407,9 +1396,9 @@ class ReportCardService }; $afterInfoY = $drawInfoRows($pdf, [ - ["Teachers' Names: ", ' '.($teacherNames !== '' ? $teacherNames : 'N/A'), 'School Year: ', ' '.$schoolYear], - ['Student Name: ', ' '.($studentName !== '' ? $studentName : 'N/A'), 'Grade: ', ' '.($gradeLabel !== '' ? $gradeLabel : 'N/A')], - ['Term: ', ' '.$semFriendly, 'Date: ', ' '.$today], + ["Teachers' Names: ", ' ' . ($teacherNames !== '' ? $teacherNames : 'N/A'), 'School Year: ', ' ' . $schoolYear], + ['Student Name: ', ' ' . ($studentName !== '' ? $studentName : 'N/A'), 'Grade: ', ' ' . ($gradeLabel !== '' ? $gradeLabel : 'N/A')], + ['Term: ', ' ' . $semFriendly, 'Date: ', ' ' . $today], ]); $pdf->SetY($afterInfoY); @@ -1486,7 +1475,7 @@ class ReportCardService $pdf->Rect($x, $startY, $statW, $statH); $pdf->SetXY($x + 2, $startY + 3); $pdf->SetFont('Helvetica', 'B', 11); - $pdf->Write(5, $lbl.' '); + $pdf->Write(5, $lbl . ' '); $pdf->SetFont('Helvetica', '', 11); $pdf->Write(5, $val); } @@ -1494,7 +1483,7 @@ class ReportCardService $effectiveSecond = $secondSemScore ?? $data['score']['semester_score'] ?? $data['total_score'] ?? null; $finalScoreVal = $finalAverage; - if (! is_numeric($finalScoreVal)) { + if (!is_numeric($finalScoreVal)) { $finalScoreVal = (is_numeric($firstSemScore) && is_numeric($effectiveSecond)) ? number_format(((float) $firstSemScore + (float) $effectiveSecond) / 2, 1) : $numFmt($effectiveSecond); @@ -1509,8 +1498,8 @@ class ReportCardService $pdf->Rect($x, $y, $w, $h); $pdf->SetXY($x + $pad, $y + 3); $pdf->SetFont('Helvetica', 'B', 11); - $pdf->Write(5, $label.' '); - $labelWidth = $pdf->GetStringWidth($label.' '); + $pdf->Write(5, $label . ' '); + $labelWidth = $pdf->GetStringWidth($label . ' '); $pdf->SetFont('Helvetica', '', 12); $pdf->SetXY($x + 2 + $labelWidth, $y + 3); $pdf->Write(5, $value); @@ -1518,14 +1507,14 @@ class ReportCardService if ($semNum === 2) { $firstLabel = ' 1st Semester Grade:'; - $firstValue = $numFmt($firstSemScore).'/100'; + $firstValue = $numFmt($firstSemScore) . '/100'; $secondLabel = ' 2nd Semester Grade:'; - $secondValue = $numFmt($effectiveSecond).'/100'; + $secondValue = $numFmt($effectiveSecond) . '/100'; $drawGradeCell($pdf, $gradeX, $gradeY, $gradeCellWidth, $gradeCellHeight, $firstLabel, $firstValue, $gradePad); $drawGradeCell($pdf, $gradeX + $gradeCellWidth, $gradeY, $gradeCellWidth, $gradeCellHeight, $secondLabel, $secondValue, $gradePad); } else { $gradeLabel = ' 1st Semester Grade:'; - $gradeValue = $numFmt($effectiveSecond).'/100'; + $gradeValue = $numFmt($effectiveSecond) . '/100'; $drawGradeCell($pdf, $gradeX, $gradeY, $gradeCellWidth, $gradeCellHeight, $gradeLabel, $gradeValue, $gradePad); } $pdf->SetY($gradeY + $gradeCellHeight); @@ -1534,7 +1523,7 @@ class ReportCardService $finalScoreEndY = null; if ($semNum === 2) { $finalLabel = 'Final Score****:'; - $finalValue = (is_string($finalScoreVal) ? $finalScoreVal : $numFmt($finalScoreVal)).'/100'; + $finalValue = (is_string($finalScoreVal) ? $finalScoreVal : $numFmt($finalScoreVal)) . '/100'; $finalCellWidth = 65; $finalCellHeight = $finalScoreRowHeight; $finalX = $pdf->GetX(); @@ -1543,8 +1532,8 @@ class ReportCardService $finalPad = max(0, 2 - (4 * 0.3528)); $pdf->SetXY($finalX + $finalPad, $finalY + 3); $pdf->SetFont('Helvetica', 'B', 11); - $pdf->Write(5, ' '.$finalLabel.' '); - $finalLabelWidth = $pdf->GetStringWidth(' '.$finalLabel.' '); + $pdf->Write(5, ' ' . $finalLabel . ' '); + $finalLabelWidth = $pdf->GetStringWidth(' ' . $finalLabel . ' '); $pdf->SetFont('Helvetica', '', 12); $pdf->SetXY($finalX + 2 + $finalLabelWidth, $finalY + 3); $pdf->Write(5, $finalValue); @@ -1556,11 +1545,11 @@ class ReportCardService $examLegendLabel = ($semNum === 1) ? 'Midterm Exam' : 'Final Exam'; $legendLines = [ "(*) {$examLegendLabel} (Weight: 60% of semester score)", - '(**) PTAP - Participation, Tests, Assignments, Projects (Weight: 20%)', + "(**) PTAP - Participation, Tests, Assignments, Projects (Weight: 20%)", "(***) Attendance = ({$totalDays} - Total Absences + One Sick Day) / {$totalDays} ) x 100 (Weight: 20%)", ]; if ($semNum === 2) { - $legendLines[] = '(****) Final Score = (1st Semester Score + 2nd Semester Score) / 2'; + $legendLines[] = "(****) Final Score = (1st Semester Score + 2nd Semester Score) / 2"; } $legendLines[] = ['text' => 'If you have any questions, please contact the school via email at alrahma.isgl@gmail.com', 'bold' => true]; $lineHeight = 4; @@ -1619,7 +1608,6 @@ class ReportCardService return $path; } } - return null; } } diff --git a/app/Services/Reports/SlipPrinterConfigService.php b/app/Services/Reports/SlipPrinterConfigService.php index 8700234a..3bed6d80 100644 --- a/app/Services/Reports/SlipPrinterConfigService.php +++ b/app/Services/Reports/SlipPrinterConfigService.php @@ -20,7 +20,7 @@ class SlipPrinterConfigService if ($userId && $userId > 0) { $user = User::query()->select('firstname', 'lastname')->find($userId); if ($user) { - $full = trim(($user->firstname ?? '').' '.($user->lastname ?? '')); + $full = trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? '')); if ($full !== '') { return $full; } @@ -40,7 +40,6 @@ class SlipPrinterConfigService return $val; } } - return $default; }; diff --git a/app/Services/Reports/SlipPrinterFormatterService.php b/app/Services/Reports/SlipPrinterFormatterService.php index b2ed7d5f..fee957c4 100644 --- a/app/Services/Reports/SlipPrinterFormatterService.php +++ b/app/Services/Reports/SlipPrinterFormatterService.php @@ -15,16 +15,13 @@ class SlipPrinterFormatterService } if (preg_match('/^\d{1,2}\/\d{1,2}\/\d{4}$/', $value)) { $dt = \DateTime::createFromFormat('!m/d/Y', $value); - return $dt ? $dt->format('Y-m-d') : null; } if (preg_match('/^\d{1,2}-\d{1,2}-\d{4}$/', $value)) { $dt = \DateTime::createFromFormat('!m-d-Y', $value); - return $dt ? $dt->format('Y-m-d') : null; } $ts = strtotime($value); - return $ts ? date('Y-m-d', $ts) : null; } @@ -35,7 +32,6 @@ class SlipPrinterFormatterService return null; } $ts = strtotime($value); - return $ts ? date('H:i:s', $ts) : null; } @@ -46,7 +42,6 @@ class SlipPrinterFormatterService return ''; } $ts = strtotime($value); - return $ts ? date('m/d/Y', $ts) : ''; } @@ -58,9 +53,8 @@ class SlipPrinterFormatterService } $ts = strtotime($value); if ($ts === false) { - $ts = strtotime('today '.$value); + $ts = strtotime('today ' . $value); } - return $ts ? date('h:i A', $ts) : ''; } @@ -70,19 +64,17 @@ class SlipPrinterFormatterService if (strlen($line) > $width) { return substr($line, 0, $width); } - - return $line.str_repeat(' ', $width - strlen($line)); + return $line . str_repeat(' ', $width - strlen($line)); } public function buildSlipLines(array $data, int $width): array { $lines = []; - $lines[] = $this->fitLine('Student Name: '.(string) ($data['student_name'] ?? ''), $width); - $lines[] = $this->fitLine('Date: '.(string) ($data['date'] ?? '').' Time In: '.(string) ($data['time_in'] ?? ''), $width); - $lines[] = $this->fitLine('Grade: '.(string) ($data['grade'] ?? ''), $width); - $lines[] = $this->fitLine('Reason: '.(string) ($data['reason'] ?? ''), $width); - $lines[] = $this->fitLine('Admin: '.(string) ($data['admin_name'] ?? ''), $width); - + $lines[] = $this->fitLine('Student Name: ' . (string) ($data['student_name'] ?? ''), $width); + $lines[] = $this->fitLine('Date: ' . (string) ($data['date'] ?? '') . ' Time In: ' . (string) ($data['time_in'] ?? ''), $width); + $lines[] = $this->fitLine('Grade: ' . (string) ($data['grade'] ?? ''), $width); + $lines[] = $this->fitLine('Reason: ' . (string) ($data['reason'] ?? ''), $width); + $lines[] = $this->fitLine('Admin: ' . (string) ($data['admin_name'] ?? ''), $width); return $lines; } } diff --git a/app/Services/Reports/SlipPrinterPdfService.php b/app/Services/Reports/SlipPrinterPdfService.php index 3c5a7380..e2bdd688 100644 --- a/app/Services/Reports/SlipPrinterPdfService.php +++ b/app/Services/Reports/SlipPrinterPdfService.php @@ -8,7 +8,9 @@ use Dompdf\Options; class SlipPrinterPdfService { - public function __construct(private SlipPrinterConfigService $configService) {} + public function __construct(private SlipPrinterConfigService $configService) + { + } public function render(array $data, array $lines, array $options = []): array { @@ -61,7 +63,7 @@ class SlipPrinterPdfService 'h_mm' => $hMm, ]); - $optionsObj = new Options; + $optionsObj = new Options(); $optionsObj->set('isRemoteEnabled', true); $optionsObj->set('defaultFont', 'Courier'); @@ -74,7 +76,7 @@ class SlipPrinterPdfService $dompdf->setPaper([0, 0, $wPt, $hPt]); $dompdf->render(); - $filename = 'LateSlip_'.preg_replace('/[^A-Za-z0-9]+/', '_', (string) ($data['student_name'] ?? 'slip')).'_'.date('Ymd_His').'.pdf'; + $filename = 'LateSlip_' . preg_replace('/[^A-Za-z0-9]+/', '_', (string) ($data['student_name'] ?? 'slip')) . '_' . date('Ymd_His') . '.pdf'; return [ 'content' => $dompdf->output(), diff --git a/app/Services/Reports/SlipPrinterService.php b/app/Services/Reports/SlipPrinterService.php index 518ffc03..553e72b0 100644 --- a/app/Services/Reports/SlipPrinterService.php +++ b/app/Services/Reports/SlipPrinterService.php @@ -10,7 +10,8 @@ class SlipPrinterService private SlipPrinterConfigService $configService, private SlipPrinterFormatterService $formatter, private SlipPrinterPdfService $pdfService - ) {} + ) { + } public function print(array $input, ?int $userId): array { @@ -44,7 +45,7 @@ class SlipPrinterService return [ 'ok' => true, - 'text' => $header.$body.$footer, + 'text' => $header . $body . $footer, 'width' => $width, ]; } @@ -96,7 +97,7 @@ class SlipPrinterService public function reprint(int $id, ?int $userId): array { $row = LateSlipLog::query()->find($id); - if (! $row) { + if (!$row) { return ['ok' => false, 'message' => 'Slip not found.']; } @@ -172,7 +173,6 @@ class SlipPrinterService { $cfg = $this->configService->printerConfig(); $width = (int) ($cfg['chars_per_line'] ?? 48); - return $width > 0 ? $width : 48; } diff --git a/app/Services/Reports/Stickers/StickerPresetService.php b/app/Services/Reports/Stickers/StickerPresetService.php index 7e0093b3..c1a84c65 100644 --- a/app/Services/Reports/Stickers/StickerPresetService.php +++ b/app/Services/Reports/Stickers/StickerPresetService.php @@ -14,10 +14,9 @@ class StickerPresetService ]; return array_map(static function (array $row): array { - $row['title'] = $row['title'] ?? ($row['label'] ?? ($row['value'].' mm')); + $row['title'] = $row['title'] ?? ($row['label'] ?? ($row['value'] . ' mm')); $row['text'] = $row['text'] ?? $row['title']; $row['per_page'] = $row['per_page'] ?? ($row['ppg'] ?? null); - return $row; }, $rows); } diff --git a/app/Services/Reports/Stickers/StickerPrintService.php b/app/Services/Reports/Stickers/StickerPrintService.php index 74278420..f4b0ebf9 100644 --- a/app/Services/Reports/Stickers/StickerPrintService.php +++ b/app/Services/Reports/Stickers/StickerPrintService.php @@ -6,7 +6,9 @@ use Illuminate\Support\Facades\Log; class StickerPrintService { - public function __construct(private StickerQueryService $queryService) {} + public function __construct(private StickerQueryService $queryService) + { + } public function generate(array $payload): array { @@ -21,7 +23,7 @@ class StickerPrintService if ($studentId > 0) { $student = $this->queryService->findStudent($studentId); - if (! $student) { + if (!$student) { return ['ok' => false, 'message' => 'Student not found.']; } $students = [$student]; @@ -100,7 +102,7 @@ class StickerPrintService $minPt = 8; $hPad = 2; - $fullName = trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')) ?: 'Student'; + $fullName = trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')) ?: 'Student'; $bestPt = $maxPt; $textW = 0.0; @@ -156,7 +158,6 @@ class StickerPrintService for ($k = 0; $k < $qty; $k++) { $printList[] = $students[0]; } - return $printList; } @@ -220,19 +221,19 @@ class StickerPrintService || (abs($stickerWidth - 100.0) < 0.6 && abs($stickerHeight - 24.5) < 0.6); if ($isXSmallPreset) { - if (! $marginLeftProvided) { + if (!$marginLeftProvided) { $marginLeft = 4.0; - if (! $marginRightProvided) { + if (!$marginRightProvided) { $marginRight = 4.0; } } - if (! $marginRightProvided && $marginRight < 4.0) { + if (!$marginRightProvided && $marginRight < 4.0) { $marginRight = 4.0; } - if (! $gapXProvided) { + if (!$gapXProvided) { $gapX = 0.0; } - if (! $gapYProvided) { + if (!$gapYProvided) { $gapY = 0.0; } } diff --git a/app/Services/Reports/Stickers/StickerQueryService.php b/app/Services/Reports/Stickers/StickerQueryService.php index 68a37376..a363bacc 100644 --- a/app/Services/Reports/Stickers/StickerQueryService.php +++ b/app/Services/Reports/Stickers/StickerQueryService.php @@ -6,7 +6,9 @@ use Illuminate\Support\Facades\DB; class StickerQueryService { - public function __construct(private StickerContextService $context) {} + public function __construct(private StickerContextService $context) + { + } public function resolveSchoolYear(?string $schoolYear): string { @@ -106,8 +108,7 @@ class StickerQueryService if ($sectionName === '') { return false; } - - return ! preg_match('/^(youth|kg)(?:\b|-)/i', $sectionName); + return !preg_match('/^(youth|kg)(?:\b|-)/i', $sectionName); })); } } diff --git a/app/Services/Roles/PermissionCrudService.php b/app/Services/Roles/PermissionCrudService.php index 5fa38fe1..6c57bdb4 100644 --- a/app/Services/Roles/PermissionCrudService.php +++ b/app/Services/Roles/PermissionCrudService.php @@ -17,7 +17,7 @@ class PermissionCrudService return Permission::query()->create($data); }); } catch (\Throwable $e) { - Log::error('Permission create failed: '.$e->getMessage()); + Log::error('Permission create failed: ' . $e->getMessage()); throw $e; } } @@ -30,11 +30,10 @@ class PermissionCrudService return DB::transaction(function () use ($permission, $data) { $permission->fill($data); $permission->save(); - return $permission; }); } catch (\Throwable $e) { - Log::error('Permission update failed: '.$e->getMessage()); + Log::error('Permission update failed: ' . $e->getMessage()); throw $e; } } @@ -46,7 +45,7 @@ class PermissionCrudService $permission->delete(); }); } catch (\Throwable $e) { - Log::error('Permission delete failed: '.$e->getMessage()); + Log::error('Permission delete failed: ' . $e->getMessage()); throw $e; } } diff --git a/app/Services/Roles/RoleAssignmentService.php b/app/Services/Roles/RoleAssignmentService.php index 6268e57f..8c55dd8e 100644 --- a/app/Services/Roles/RoleAssignmentService.php +++ b/app/Services/Roles/RoleAssignmentService.php @@ -3,6 +3,7 @@ namespace App\Services\Roles; use App\Models\Role; +use App\Models\Staff; use App\Models\User; use App\Models\UserRole; use Illuminate\Support\Facades\DB; @@ -10,7 +11,9 @@ use Illuminate\Support\Facades\Log; class RoleAssignmentService { - public function __construct(private RoleStaffService $staffService) {} + public function __construct(private RoleStaffService $staffService) + { + } /** @param int[] $roleIds */ public function assignRoles(int $userId, array $roleIds, ?int $adminId = null): array @@ -18,7 +21,7 @@ class RoleAssignmentService $roleIds = array_values(array_unique(array_filter(array_map('intval', $roleIds), fn ($id) => $id > 0))); $user = User::query()->find($userId); - if (! $user) { + if (!$user) { return ['ok' => false, 'message' => 'User not found.']; } @@ -35,7 +38,7 @@ class RoleAssignmentService } }); } catch (\Throwable $e) { - Log::error('Role assignment failed: '.$e->getMessage()); + Log::error('Role assignment failed: ' . $e->getMessage()); throw $e; } diff --git a/app/Services/Roles/RoleCrudService.php b/app/Services/Roles/RoleCrudService.php index 4a629871..a11b0570 100644 --- a/app/Services/Roles/RoleCrudService.php +++ b/app/Services/Roles/RoleCrudService.php @@ -17,7 +17,7 @@ class RoleCrudService return Role::query()->create($data); }); } catch (\Throwable $e) { - Log::error('Role create failed: '.$e->getMessage()); + Log::error('Role create failed: ' . $e->getMessage()); throw $e; } } @@ -30,11 +30,10 @@ class RoleCrudService return DB::transaction(function () use ($role, $data) { $role->fill($data); $role->save(); - return $role; }); } catch (\Throwable $e) { - Log::error('Role update failed: '.$e->getMessage()); + Log::error('Role update failed: ' . $e->getMessage()); throw $e; } } @@ -46,7 +45,7 @@ class RoleCrudService $role->delete(); }); } catch (\Throwable $e) { - Log::error('Role delete failed: '.$e->getMessage()); + Log::error('Role delete failed: ' . $e->getMessage()); throw $e; } } @@ -58,7 +57,7 @@ class RoleCrudService $route = trim((string) ($payload['dashboard_route'] ?? '')); $desc = trim((string) ($payload['description'] ?? '')); $priority = (int) ($payload['priority'] ?? 0); - $isActive = ! empty($payload['is_active']) ? 1 : 0; + $isActive = !empty($payload['is_active']) ? 1 : 0; $name = strtolower($rawName); $dashboardRoute = strtolower($route); @@ -93,11 +92,11 @@ class RoleCrudService $query->where('id', '!=', $ignoreId); } - if (! $query->exists()) { + if (!$query->exists()) { return $slug; } - $slug = $baseSlug.'_'.$i; + $slug = $baseSlug . '_' . $i; $i++; if ($i > 100000) { diff --git a/app/Services/Roles/RoleDashboardService.php b/app/Services/Roles/RoleDashboardService.php index 74406ff6..f5a6f119 100644 --- a/app/Services/Roles/RoleDashboardService.php +++ b/app/Services/Roles/RoleDashboardService.php @@ -10,7 +10,7 @@ class RoleDashboardService public function bestDashboardRouteFor(array $roleKeys): string { $rows = Role::findByNamesOrSlugs($roleKeys); - if (! empty($rows)) { + if (!empty($rows)) { return $rows[0]->dashboard_route ?? '/landing_page/guest_dashboard'; } diff --git a/app/Services/Roles/RolePermissionService.php b/app/Services/Roles/RolePermissionService.php index 4d01060d..c299adc3 100644 --- a/app/Services/Roles/RolePermissionService.php +++ b/app/Services/Roles/RolePermissionService.php @@ -58,11 +58,11 @@ class RolePermissionService } $data = [ - 'can_create' => ! empty($crudValues['create']) ? 1 : 0, - 'can_read' => ! empty($crudValues['read']) ? 1 : 0, - 'can_update' => ! empty($crudValues['update']) ? 1 : 0, - 'can_delete' => ! empty($crudValues['delete']) ? 1 : 0, - 'can_manage' => ! empty($crudValues['manage']) ? 1 : 0, + 'can_create' => !empty($crudValues['create']) ? 1 : 0, + 'can_read' => !empty($crudValues['read']) ? 1 : 0, + 'can_update' => !empty($crudValues['update']) ? 1 : 0, + 'can_delete' => !empty($crudValues['delete']) ? 1 : 0, + 'can_manage' => !empty($crudValues['manage']) ? 1 : 0, ]; if ($existing->has($permissionId)) { @@ -79,7 +79,7 @@ class RolePermissionService } foreach ($existing as $permissionId => $row) { - if (! array_key_exists((string) $permissionId, $permissions) && ! array_key_exists((int) $permissionId, $permissions)) { + if (!array_key_exists((string) $permissionId, $permissions) && !array_key_exists((int) $permissionId, $permissions)) { RolePermission::query() ->where('role_id', $roleId) ->where('permission_id', $permissionId) @@ -88,7 +88,7 @@ class RolePermissionService } }); } catch (\Throwable $e) { - Log::error('Role permission save failed: '.$e->getMessage()); + Log::error('Role permission save failed: ' . $e->getMessage()); throw $e; } } diff --git a/app/Services/Roles/RoleQueryService.php b/app/Services/Roles/RoleQueryService.php index b4a2c60f..aba59176 100644 --- a/app/Services/Roles/RoleQueryService.php +++ b/app/Services/Roles/RoleQueryService.php @@ -40,19 +40,19 @@ class RoleQueryService 'roles.updated_at', ]); - if (! empty($filters['search'])) { + if (!empty($filters['search'])) { $search = trim((string) $filters['search']); $query->where(function (Builder $q) use ($search) { - $q->where('roles.name', 'like', '%'.$search.'%') - ->orWhere('roles.slug', 'like', '%'.$search.'%') - ->orWhere('roles.description', 'like', '%'.$search.'%'); + $q->where('roles.name', 'like', '%' . $search . '%') + ->orWhere('roles.slug', 'like', '%' . $search . '%') + ->orWhere('roles.description', 'like', '%' . $search . '%'); }); } $sortBy = (string) ($filters['sort_by'] ?? 'name'); $sortDir = strtolower((string) ($filters['sort_dir'] ?? 'asc')) === 'desc' ? 'desc' : 'asc'; $allowed = ['name', 'slug', 'priority', 'is_active', 'created_at']; - if (! in_array($sortBy, $allowed, true)) { + if (!in_array($sortBy, $allowed, true)) { $sortBy = 'name'; } @@ -80,26 +80,26 @@ class RoleQueryService ) ->groupBy('users.id', 'users.firstname', 'users.lastname', 'users.email', 'users.account_id'); - if (! empty($filters['search'])) { + if (!empty($filters['search'])) { $search = trim((string) $filters['search']); $query->where(function ($q) use ($search) { - $q->where('users.firstname', 'like', '%'.$search.'%') - ->orWhere('users.lastname', 'like', '%'.$search.'%') - ->orWhere('users.email', 'like', '%'.$search.'%') - ->orWhere('users.account_id', 'like', '%'.$search.'%'); + $q->where('users.firstname', 'like', '%' . $search . '%') + ->orWhere('users.lastname', 'like', '%' . $search . '%') + ->orWhere('users.email', 'like', '%' . $search . '%') + ->orWhere('users.account_id', 'like', '%' . $search . '%'); }); } $sortBy = (string) ($filters['sort_by'] ?? 'lastname'); $sortDir = strtolower((string) ($filters['sort_dir'] ?? 'asc')) === 'desc' ? 'desc' : 'asc'; $allowed = ['firstname', 'lastname', 'email', 'account_id']; - if (! in_array($sortBy, $allowed, true)) { + if (!in_array($sortBy, $allowed, true)) { $sortBy = 'lastname'; } $perPage = (int) ($filters['per_page'] ?? 20); $perPage = $perPage > 0 ? $perPage : 20; - return $query->orderBy('users.'.$sortBy, $sortDir)->paginate($perPage); + return $query->orderBy('users.' . $sortBy, $sortDir)->paginate($perPage); } } diff --git a/app/Services/Roles/RoleStaffService.php b/app/Services/Roles/RoleStaffService.php index abf1d0d1..17473e0b 100644 --- a/app/Services/Roles/RoleStaffService.php +++ b/app/Services/Roles/RoleStaffService.php @@ -16,9 +16,9 @@ class RoleStaffService static fn ($role) => trim((string) $role), $newRoleNames ), - static fn ($role) => $role !== '' && ! in_array(strtolower($role), $excludedRoles, true) + static fn ($role) => $role !== '' && !in_array(strtolower($role), $excludedRoles, true) ))); - $activeRole = ! empty($staffRoles) ? strtolower((string) $staffRoles[0]) : 'inactive'; + $activeRole = !empty($staffRoles) ? strtolower((string) $staffRoles[0]) : 'inactive'; $email = $this->generateUniqueStaffEmail($user->firstname ?? '', $user->lastname ?? '', (int) $user->id); @@ -34,7 +34,7 @@ class RoleStaffService ]; $saved = Staff::upsertStaff($payload); - if (! $saved) { + if (!$saved) { Log::warning('Failed to upsert staff record.', ['user_id' => $user->id]); } } @@ -50,7 +50,7 @@ class RoleStaffService $out = ''; foreach ($roles as $role) { - $next = $out === '' ? $role : $out.', '.$role; + $next = $out === '' ? $role : $out . ', ' . $role; if (strlen($next) > $maxLength) { break; } @@ -73,18 +73,18 @@ class RoleStaffService $email = ''; for ($i = $min; $i <= $max; $i++) { - $base = substr($firstname, 0, $i).$lastname; - $email = $base.$domain; + $base = substr($firstname, 0, $i) . $lastname; + $email = $base . $domain; $exists = Staff::query() ->where('email', $email) ->where('user_id', '!=', $userId) ->exists(); - if (! $exists) { + if (!$exists) { return $email; } } - return $base.$userId.$domain; + return $base . $userId . $domain; } } diff --git a/app/Services/Roles/RoleSwitchService.php b/app/Services/Roles/RoleSwitchService.php index 52fdbb32..da2c05bf 100644 --- a/app/Services/Roles/RoleSwitchService.php +++ b/app/Services/Roles/RoleSwitchService.php @@ -8,12 +8,13 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class RoleSwitchService { - public function __construct(private RoleDashboardService $dashboardService) {} + public function __construct(private RoleDashboardService $dashboardService) + { + } public function getUserRoleNames(int $userId): array { $roles = UserRole::getRolesByUserId($userId); - return array_values(array_filter(array_map(fn ($r) => (string) ($r['role_name'] ?? ''), $roles))); } diff --git a/app/Services/School/AccountEventService.php b/app/Services/School/AccountEventService.php index 0cc05b98..36f4f24e 100644 --- a/app/Services/School/AccountEventService.php +++ b/app/Services/School/AccountEventService.php @@ -20,7 +20,8 @@ class AccountEventService public function __construct( private EmailService $emailService, private UserNotificationDispatchService $notifier - ) {} + ) { + } public function newAccountAdded(array $userData): array { @@ -28,7 +29,7 @@ class AccountEventService $message = $this->renderEmail('emails/welcome_user', ['user' => $userData], $subject); $sent = false; - if (! empty($userData['email'])) { + if (!empty($userData['email'])) { $sent = $this->emailService->send( (string) $userData['email'], $subject, @@ -40,7 +41,7 @@ class AccountEventService $supportMessage = $this->renderEmail('emails/support_new_account', ['user' => $userData], $subject); $this->emailService->send( 'support@alrahmaisgl.org', - 'New Account Created: '.trim((string) ($userData['firstname'] ?? '').' '.(string) ($userData['lastname'] ?? '')), + 'New Account Created: ' . trim((string) ($userData['firstname'] ?? '') . ' ' . (string) ($userData['lastname'] ?? '')), $supportMessage, 'notifications' ); @@ -52,14 +53,13 @@ class AccountEventService public function studentRegistered(array $data): array { - if (empty($data['parents']) || ! is_array($data['parents'])) { + if (empty($data['parents']) || !is_array($data['parents'])) { Log::warning('StudentRegistered: missing parent data'); - return ['ok' => false, 'message' => 'Missing parent data.']; } - $studentFullName = trim((string) ($data['firstname'] ?? '').' '.(string) ($data['lastname'] ?? '')); - if (! empty($data['parents']['user_id'])) { + $studentFullName = trim((string) ($data['firstname'] ?? '') . ' ' . (string) ($data['lastname'] ?? '')); + if (!empty($data['parents']['user_id'])) { $title = 'Your child has been registered'; $msg = "{$studentFullName} has been successfully registered to Al Rahma Sunday School."; $this->notifier->notifyUser((int) $data['parents']['user_id'], $title, $msg, ['in_app', 'email'], 'registration', 'parent'); @@ -100,21 +100,18 @@ class AccountEventService public function userRegistered(array $user): array { $this->notifier->notifyUser((int) ($user['id'] ?? 0), 'Welcome!', 'Thanks for registering with our school system.', ['in_app', 'email'], 'notifications', 'parent'); - return ['ok' => true]; } public function userProfileUpdated(array $user): array { $this->notifier->notifyUser((int) ($user['id'] ?? 0), 'Profile Updated', 'Your profile information was successfully updated.', ['in_app'], 'notifications', 'parent'); - return ['ok' => true]; } public function userDeactivated(array $user): array { $this->notifier->notifyUser((int) ($user['id'] ?? 0), 'Account Deactivated', 'Your account has been deactivated by the administrator.', ['in_app', 'email'], 'notifications', 'parent'); - return ['ok' => true]; } @@ -123,7 +120,6 @@ class AccountEventService foreach ((array) ($data['students'] ?? []) as $student) { $this->notifier->notifyUser((int) ($student['id'] ?? 0), 'New Score Available', 'A new score has been posted.', ['in_app', 'email'], 'registration', 'student'); } - return ['ok' => true]; } @@ -140,24 +136,21 @@ class AccountEventService public function studentMarkedAbsent(array $record): array { - $msg = (string) ($record['student_name'] ?? 'Student').' was absent on '.(string) ($record['date'] ?? ''); + $msg = (string) ($record['student_name'] ?? 'Student') . ' was absent on ' . (string) ($record['date'] ?? ''); $this->notifier->notifyUser((int) ($record['parent_id'] ?? 0), 'Absence Notification', $msg, ['in_app', 'email'], 'registration', 'parent'); - return ['ok' => true]; } public function studentMarkedLate(array $record): array { - $msg = (string) ($record['student_name'] ?? 'Student').' was late on '.(string) ($record['date'] ?? ''); + $msg = (string) ($record['student_name'] ?? 'Student') . ' was late on ' . (string) ($record['date'] ?? ''); $this->notifier->notifyUser((int) ($record['parent_id'] ?? 0), 'Late Notification', $msg, ['in_app', 'email'], 'registration', 'parent'); - return ['ok' => true]; } public function paymentMissed(array $user): array { $this->notifier->notifyUser((int) ($user['id'] ?? 0), 'Payment Missed', 'You have missed a scheduled payment. Please settle your balance.', ['in_app', 'email'], 'payment', 'parent'); - return ['ok' => true]; } @@ -166,15 +159,13 @@ class AccountEventService foreach ((array) ($data['students'] ?? []) as $student) { $this->notifier->notifyUser((int) ($student['id'] ?? 0), 'Schedule Update', 'Your class schedule has been updated.', ['in_app'], 'notifications', 'student'); } - return ['ok' => true]; } public function newMessageReceived(array $data): array { - $msg = 'You have a new message from '.(string) ($data['sender_name'] ?? ''); + $msg = 'You have a new message from ' . (string) ($data['sender_name'] ?? ''); $this->notifier->notifyUser((int) ($data['recipient_id'] ?? 0), 'New Message Received', $msg, ['in_app'], 'notifications', 'parent'); - return ['ok' => true]; } @@ -189,7 +180,6 @@ class AccountEventService foreach ($users as $user) { $this->notifier->notifyUser((int) ($user['id'] ?? 0), (string) ($data['title'] ?? ''), (string) ($data['message'] ?? ''), ['in_app'], 'notifications', $targetGroup); } - return ['ok' => true]; } @@ -215,10 +205,10 @@ class AccountEventService } DB::transaction(function () use ($userData, $userId): void { - $familyCode = 'FAM-'.$userId; + $familyCode = 'FAM-' . $userId; $family = Family::query()->where('family_code', $familyCode)->first(); - if (! $family) { - $householdName = trim('Family of '.((string) ($userData['firstname'] ?? '').' '.(string) ($userData['lastname'] ?? ''))); + if (!$family) { + $householdName = trim('Family of ' . ((string) ($userData['firstname'] ?? '') . ' ' . (string) ($userData['lastname'] ?? ''))); $family = Family::query()->create([ 'family_code' => $familyCode, 'household_name' => $householdName, @@ -262,12 +252,12 @@ class AccountEventService { try { $currentYear = (string) Configuration::getConfigValueByKey('school_year'); - if (! preg_match('/^(\d{4})-(\d{4})$/', $currentYear, $m)) { + if (!preg_match('/^(\d{4})-(\d{4})$/', $currentYear, $m)) { return; } $y1 = (int) $m[1]; $y2 = (int) $m[2]; - $nextYear = ($y1 + 1).'-'.($y2 + 1); + $nextYear = ($y1 + 1) . '-' . ($y2 + 1); $rows = DB::table('students as s') ->select('s.id as student_id', 'sc.class_section_id', 'fall.semester_score as fall_score', 'spring.semester_score as spring_score') @@ -319,7 +309,7 @@ class AccountEventService ]); } } catch (\Throwable $e) { - Log::error('Promotion queue build failed: '.$e->getMessage()); + Log::error('Promotion queue build failed: ' . $e->getMessage()); } } @@ -327,6 +317,6 @@ class AccountEventService { Log::debug('Skipping Blade email template', ['view' => $viewName]); - return '

'.e($fallbackTitle).'

'; + return '

' . e($fallbackTitle) . '

'; } } diff --git a/app/Services/School/EnrollmentEventService.php b/app/Services/School/EnrollmentEventService.php index 8ef92418..b61719cb 100644 --- a/app/Services/School/EnrollmentEventService.php +++ b/app/Services/School/EnrollmentEventService.php @@ -13,7 +13,8 @@ class EnrollmentEventService private EmailService $emailService, private UserNotificationDispatchService $notifier, private ApplicationUrlService $urls, - ) {} + ) { + } public function admissionUnderReview(array $parentData, array $students): array { @@ -178,7 +179,7 @@ class EnrollmentEventService 'parentName' => $parentName, 'studentName' => $studentName, 'withdrawalDate' => $parentData['withdrawal_date'] ?? ($parentData['date'] ?? ''), - 'withdrawals' => ! empty($withdrawals) ? $withdrawals : null, + 'withdrawals' => !empty($withdrawals) ? $withdrawals : null, 'portalLink' => $parentData['portalLink'] ?? $this->urls->webLoginUrl(), 'title' => 'Withdrawal Confirmed', ]; @@ -277,16 +278,16 @@ class EnrollmentEventService private function parentName(array $parentData): string { - return trim((string) ($parentData['firstname'] ?? '').' '.(string) ($parentData['lastname'] ?? '')); + return trim((string) ($parentData['firstname'] ?? '') . ' ' . (string) ($parentData['lastname'] ?? '')); } private function studentNameData(array $studentdata, array $parentData) { $names = []; foreach ($studentdata as $s) { - $nm = ! empty($s['name']) + $nm = !empty($s['name']) ? trim((string) $s['name']) - : trim((string) ($s['firstname'] ?? '').' '.(string) ($s['lastname'] ?? '')); + : trim((string) ($s['firstname'] ?? '') . ' ' . (string) ($s['lastname'] ?? '')); if ($nm !== '') { $names[] = $nm; } @@ -298,7 +299,6 @@ class EnrollmentEventService if (count($names) === 1) { return $names[0]; } - return $names; } @@ -306,9 +306,9 @@ class EnrollmentEventService { $names = []; foreach ($studentdata as $s) { - $nm = ! empty($s['name']) + $nm = !empty($s['name']) ? trim((string) $s['name']) - : trim((string) ($s['firstname'] ?? '').' '.(string) ($s['lastname'] ?? '')); + : trim((string) ($s['firstname'] ?? '') . ' ' . (string) ($s['lastname'] ?? '')); if ($nm !== '') { $names[] = $nm; } @@ -321,20 +321,19 @@ class EnrollmentEventService return $names[0]; } if (count($names) === 2) { - return $names[0].' and '.$names[1]; + return $names[0] . ' and ' . $names[1]; } $last = array_pop($names); - - return implode(', ', $names).', and '.$last; + return implode(', ', $names) . ', and ' . $last; } private function studentDetails(array $studentdata): array { $details = []; foreach ($studentdata as $s) { - $nm = ! empty($s['name']) + $nm = !empty($s['name']) ? trim((string) $s['name']) - : trim((string) ($s['firstname'] ?? '').' '.(string) ($s['lastname'] ?? '')); + : trim((string) ($s['firstname'] ?? '') . ' ' . (string) ($s['lastname'] ?? '')); if ($nm === '') { continue; } @@ -346,7 +345,6 @@ class EnrollmentEventService 'startDate' => $s['start_date'] ?? '', ]; } - return $details; } @@ -354,9 +352,9 @@ class EnrollmentEventService { $withdrawals = []; foreach ($studentdata as $s) { - $nm = ! empty($s['name']) + $nm = !empty($s['name']) ? trim((string) $s['name']) - : trim((string) ($s['firstname'] ?? '').' '.(string) ($s['lastname'] ?? '')); + : trim((string) ($s['firstname'] ?? '') . ' ' . (string) ($s['lastname'] ?? '')); if ($nm === '') { continue; } @@ -368,7 +366,6 @@ class EnrollmentEventService ]; } } - return $withdrawals; } @@ -376,9 +373,9 @@ class EnrollmentEventService { $rows = []; foreach ($studentdata as $s) { - $nm = ! empty($s['name']) + $nm = !empty($s['name']) ? trim((string) $s['name']) - : trim((string) ($s['firstname'] ?? '').' '.(string) ($s['lastname'] ?? '')); + : trim((string) ($s['firstname'] ?? '') . ' ' . (string) ($s['lastname'] ?? '')); if ($nm === '') { continue; } @@ -387,7 +384,6 @@ class EnrollmentEventService 'reason' => $s['reason'] ?? null, ]; } - return $rows; } @@ -403,15 +399,13 @@ class EnrollmentEventService { if ($to === '') { Log::warning('Enrollment event: missing recipient email', ['subject' => $subject]); - return ['ok' => false, 'message' => 'Missing recipient email.']; } $ok = $this->emailService->send($to, $subject, $html, $fromKey); - if (! $ok) { + if (!$ok) { Log::error('Enrollment event email failed', ['to' => $to, 'subject' => $subject]); } - return ['ok' => $ok]; } @@ -419,6 +413,6 @@ class EnrollmentEventService { Log::debug('Skipping Blade email template', ['view' => $viewName]); - return '

'.e($fallbackTitle).'

'; + return '

' . e($fallbackTitle) . '

'; } } diff --git a/app/Services/School/PaymentEventService.php b/app/Services/School/PaymentEventService.php index eb23383c..23e84fd4 100644 --- a/app/Services/School/PaymentEventService.php +++ b/app/Services/School/PaymentEventService.php @@ -13,21 +13,21 @@ class PaymentEventService private EmailService $emailService, private UserNotificationDispatchService $notifier, private ApplicationUrlService $urls, - ) {} + ) { + } public function paymentReceived(array $data, array $studentdata = []): array { - $parentName = trim((string) ($data['firstname'] ?? '').' '.(string) ($data['lastname'] ?? '')); + $parentName = trim((string) ($data['firstname'] ?? '') . ' ' . (string) ($data['lastname'] ?? '')); - $fmtMoney = static fn ($v) => '$'.number_format((float) $v, 2); + $fmtMoney = static fn ($v) => '$' . number_format((float) $v, 2); $fmtDateTz = static function (?string $s): string { - if (! $s) { + if (!$s) { return ''; } $dt = new \DateTime($s, new \DateTimeZone('UTC')); $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone()); $dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC')); - return $dt->format('m-d-Y h:i A'); }; @@ -94,33 +94,30 @@ class PaymentEventService public function extraCharge(array $data, array $studentdata = []): array { - $fmtMoney = static fn ($v) => '$'.number_format((float) $v, 2); + $fmtMoney = static fn ($v) => '$' . number_format((float) $v, 2); $fmtFromUtc = static function (?string $s, string $fmt = 'm-d-Y h:i A'): string { - if (! $s) { + if (!$s) { return ''; } try { $dt = new \DateTime($s, new \DateTimeZone('UTC')); $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone()); $dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC')); - return $dt->format($fmt); } catch (\Throwable $e) { - Log::error('extraCharge date error: '.$e->getMessage()); - + Log::error('extraCharge date error: ' . $e->getMessage()); return ''; } }; $fmtDueLocal = static function (?string $s): string { - if (! $s) { + if (!$s) { return ''; } try { if (strlen($s) <= 10) { $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone()); $dt = \DateTime::createFromFormat('Y-m-d', $s, new \DateTimeZone($tzName ?: 'UTC')); - return $dt ? $dt->format('m-d-Y') : ''; } @@ -128,22 +125,19 @@ class PaymentEventService $dt = new \DateTime($s); $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone()); $dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC')); - return $dt->format('m-d-Y h:i A'); } $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone()); $dt = new \DateTime($s, new \DateTimeZone($tzName ?: 'UTC')); - return $dt->format('m-d-Y h:i A'); } catch (\Throwable $e) { - Log::error('extraCharge due date error: '.$e->getMessage()); - + Log::error('extraCharge due date error: ' . $e->getMessage()); return ''; } }; - $parentName = trim((string) ($data['firstname'] ?? '').' '.(string) ($data['lastname'] ?? '')); + $parentName = trim((string) ($data['firstname'] ?? '') . ' ' . (string) ($data['lastname'] ?? '')); $amountSigned = (float) ($data['amount_signed'] ?? 0); $amountAbs = (float) ($data['amount_abs'] ?? abs($amountSigned)); @@ -195,7 +189,6 @@ class PaymentEventService ); $body = $this->renderEmail('emails/extra_charge_notice', $emailData, 'Account Charge Update'); - return $this->sendEmail((string) ($data['email'] ?? ''), $subject, $body, 'billing'); } @@ -211,15 +204,13 @@ class PaymentEventService { if ($to === '') { Log::warning('Payment event missing recipient email', ['subject' => $subject]); - return ['ok' => false, 'message' => 'Missing recipient email.']; } $ok = $this->emailService->send($to, $subject, $html, $fromKey); - if (! $ok) { + if (!$ok) { Log::error('Payment event email failed', ['to' => $to, 'subject' => $subject]); } - return ['ok' => $ok]; } @@ -227,6 +218,6 @@ class PaymentEventService { Log::debug('Skipping Blade email template', ['view' => $viewName]); - return '

'.e($fallbackTitle).'

'; + return '

' . e($fallbackTitle) . '

'; } } diff --git a/app/Services/SchoolIdService.php b/app/Services/SchoolIdService.php index 32af8e4b..390f1233 100644 --- a/app/Services/SchoolIdService.php +++ b/app/Services/SchoolIdService.php @@ -10,7 +10,7 @@ class SchoolIdService public function assignSchoolIdToUser(int $userId): ?string { $user = User::query()->find($userId); - if (! $user) { + if (!$user) { return null; } @@ -36,7 +36,7 @@ class SchoolIdService ->where('school_id', 'like', "STU{$year}%") ->first(); - if (! empty($row?->max_id)) { + if (!empty($row?->max_id)) { $numericPart = substr((string) $row->max_id, 5); $maxId = (int) $numericPart; } @@ -57,7 +57,7 @@ class SchoolIdService ->where('school_id', 'like', "{$year}%") ->first(); - if (! empty($row?->max_id)) { + if (!empty($row?->max_id)) { $numericPart = substr((string) $row->max_id, 2); $maxId = max($maxId, (int) $numericPart); } diff --git a/app/Services/SchoolIds/SchoolIdAssignmentService.php b/app/Services/SchoolIds/SchoolIdAssignmentService.php index 951bd5e5..c0faaba3 100644 --- a/app/Services/SchoolIds/SchoolIdAssignmentService.php +++ b/app/Services/SchoolIds/SchoolIdAssignmentService.php @@ -6,7 +6,9 @@ use App\Services\SchoolIdService; class SchoolIdAssignmentService { - public function __construct(private SchoolIdService $schoolIdService) {} + public function __construct(private SchoolIdService $schoolIdService) + { + } public function assignToUser(int $userId): ?string { diff --git a/app/Services/SchoolIds/SchoolIdGenerationService.php b/app/Services/SchoolIds/SchoolIdGenerationService.php index 3f1be635..79a02e11 100644 --- a/app/Services/SchoolIds/SchoolIdGenerationService.php +++ b/app/Services/SchoolIds/SchoolIdGenerationService.php @@ -6,7 +6,9 @@ use App\Services\SchoolIdService; class SchoolIdGenerationService { - public function __construct(private SchoolIdService $schoolIdService) {} + public function __construct(private SchoolIdService $schoolIdService) + { + } public function generateStudentId(): string { diff --git a/app/Services/SchoolYears/SchoolYearClosureService.php b/app/Services/SchoolYears/SchoolYearClosureService.php index d494acbf..6c10dc74 100644 --- a/app/Services/SchoolYears/SchoolYearClosureService.php +++ b/app/Services/SchoolYears/SchoolYearClosureService.php @@ -8,6 +8,7 @@ use App\Models\ParentAccount; use App\Models\ParentBalanceTransfer; use App\Models\SchoolYear; use App\Services\Promotions\LevelProgressionService; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Illuminate\Validation\ValidationException; @@ -18,7 +19,8 @@ class SchoolYearClosureService public function __construct( private SchoolYearResolver $resolver, private LevelProgressionService $progression - ) {} + ) { + } public function list(): array { @@ -233,7 +235,7 @@ class SchoolYearClosureService { $year = $this->findOrFail($id); $validation = $this->validateClose($id, $payload); - if (! $validation['can_close']) { + if (!$validation['can_close']) { throw ValidationException::withMessages(['school_year' => $validation['errors']]); } @@ -247,7 +249,7 @@ class SchoolYearClosureService $newYearPayload = $payload['new_school_year']; $promotionPreview = $this->buildPromotionPreview($year->name, $newYearPayload['name']); - $balances = ! empty($payload['transfer_unpaid_balances']) + $balances = !empty($payload['transfer_unpaid_balances']) ? $this->buildParentBalanceRows($year->name, $newYearPayload['name']) : ['rows' => [], 'summary' => ['net_balance_to_transfer' => 0]]; @@ -289,7 +291,7 @@ class SchoolYearClosureService Configuration::setConfigValueByKey('school_year', $newYear->name); $promotionCounts = $this->applyPromotions($promotionPreview['rows'], $newYear->name, $newYear->start_date, $actorId); - $balanceCounts = ! empty($payload['transfer_unpaid_balances']) + $balanceCounts = !empty($payload['transfer_unpaid_balances']) ? $this->applyBalanceTransfers($balances['rows'], $year->name, $newYear->name, $actorId) : [ 'transferred_parents' => 0, @@ -394,9 +396,8 @@ class SchoolYearClosureService $errors[] = 'New school year name is required.'; } - if (! $startDate || ! $endDate) { + if (!$startDate || !$endDate) { $errors[] = 'New school year start_date and end_date are required.'; - return $errors; } @@ -456,7 +457,7 @@ class SchoolYearClosureService ]; foreach ($tables as $mapping) { - if (! Schema::hasTable($mapping['table'])) { + if (!Schema::hasTable($mapping['table'])) { continue; } if (DB::table($mapping['table'])->where($mapping['column'], $schoolYear)->exists()) { @@ -489,7 +490,7 @@ class SchoolYearClosureService $assignmentByStudent = []; foreach ($assignments as $assignment) { $studentId = (int) $assignment->student_id; - if (! isset($assignmentByStudent[$studentId])) { + if (!isset($assignmentByStudent[$studentId])) { $assignmentByStudent[$studentId] = $assignment; } } @@ -505,7 +506,7 @@ class SchoolYearClosureService $enrollmentByStudent = []; foreach ($enrollments as $enrollment) { $studentId = (int) $enrollment->student_id; - if (! isset($enrollmentByStudent[$studentId])) { + if (!isset($enrollmentByStudent[$studentId])) { $enrollmentByStudent[$studentId] = $enrollment; } } @@ -520,7 +521,7 @@ class SchoolYearClosureService $decisionByStudent = []; foreach ($decisions as $decision) { $studentId = (int) $decision->student_id; - if (! isset($decisionByStudent[$studentId])) { + if (!isset($decisionByStudent[$studentId])) { $decisionByStudent[$studentId] = $decision; } } @@ -538,7 +539,7 @@ class SchoolYearClosureService foreach ($studentIds as $studentId) { $student = $students->get($studentId); - if (! $student) { + if (!$student) { continue; } @@ -598,7 +599,7 @@ class SchoolYearClosureService $row = [ 'student_id' => $studentId, - 'student_name' => trim((string) ($student->firstname ?? '').' '.(string) ($student->lastname ?? '')), + 'student_name' => trim((string) ($student->firstname ?? '') . ' ' . (string) ($student->lastname ?? '')), 'parent_id' => (int) ($student->parent_id ?? 0) ?: null, 'current_grade' => $progression['current_level_name'] ?? ($currentClass->class_name ?? null), 'current_class' => $section->class_section_name ?? null, @@ -644,7 +645,7 @@ class SchoolYearClosureService ? (float) $invoice->balance : (float) ($invoice->total_amount ?? 0) - (float) ($invoice->paid_amount ?? 0); - if (! isset($byParent[$parentId])) { + if (!isset($byParent[$parentId])) { $existing = ParentBalanceTransfer::query() ->where('parent_id', $parentId) ->where('from_school_year', $fromSchoolYear) @@ -736,7 +737,7 @@ class SchoolYearClosureService ->orderBy('class_section_id') ->first(); - if (! $section) { + if (!$section) { return [null, null]; } @@ -756,13 +757,13 @@ class SchoolYearClosureService foreach ($rows as $row) { $action = $row['promotion_action']; - if (! isset($counts[$action])) { + if (!isset($counts[$action])) { continue; } $counts[$action]++; - if (! in_array($action, ['promote', 'repeat'], true)) { + if (!in_array($action, ['promote', 'repeat'], true)) { $this->logAudit( $actorId, 'school_year_promotion_decision_applied', @@ -772,7 +773,6 @@ class SchoolYearClosureService null, ['action' => $action, 'new_school_year' => $newSchoolYear] ); - continue; } @@ -781,7 +781,7 @@ class SchoolYearClosureService ->where('school_year', $newSchoolYear) ->first(); - if (! $existingEnrollment) { + if (!$existingEnrollment) { DB::table('enrollments')->insert([ 'student_id' => $row['student_id'], 'class_section_id' => $row['target_class_section_id'], @@ -805,7 +805,7 @@ class SchoolYearClosureService ->where('class_section_id', $row['target_class_section_id']) ->exists(); - if (! $existingAssignment) { + if (!$existingAssignment) { DB::table('student_class')->insert([ 'student_id' => $row['student_id'], 'class_section_id' => $row['target_class_section_id'], @@ -950,7 +950,7 @@ class SchoolYearClosureService private function countPendingPayments(string $schoolYear): int { - if (! Schema::hasTable('payments')) { + if (!Schema::hasTable('payments')) { return 0; } @@ -978,7 +978,7 @@ class SchoolYearClosureService private function countDuplicateParentAccounts(): int { - if (! Schema::hasTable('parent_accounts')) { + if (!Schema::hasTable('parent_accounts')) { return 0; } @@ -992,11 +992,11 @@ class SchoolYearClosureService private function resolveParentName(int $parentId): ?string { $row = DB::table('users')->where('id', $parentId)->first(); - if (! $row) { + if (!$row) { return null; } - return trim((string) ($row->firstname ?? '').' '.(string) ($row->lastname ?? '')); + return trim((string) ($row->firstname ?? '') . ' ' . (string) ($row->lastname ?? '')); } private function resolveStudentNames(int $parentId, string $schoolYear): array @@ -1015,7 +1015,7 @@ class SchoolYearClosureService return DB::table('students') ->whereIn('id', $studentIds) ->get() - ->map(fn ($student) => trim((string) ($student->firstname ?? '').' '.(string) ($student->lastname ?? ''))) + ->map(fn ($student) => trim((string) ($student->firstname ?? '') . ' ' . (string) ($student->lastname ?? ''))) ->filter() ->values() ->all(); @@ -1023,7 +1023,7 @@ class SchoolYearClosureService private function presentSchoolYear(?SchoolYear $year): ?array { - if (! $year) { + if (!$year) { return null; } @@ -1048,7 +1048,7 @@ class SchoolYearClosureService ?array $newValue, ?array $metadata = null ): void { - if (! Schema::hasTable('audit_logs')) { + if (!Schema::hasTable('audit_logs')) { return; } diff --git a/app/Services/SchoolYears/SchoolYearContextService.php b/app/Services/SchoolYears/SchoolYearContextService.php index 3094b0d8..bbaf6f4b 100644 --- a/app/Services/SchoolYears/SchoolYearContextService.php +++ b/app/Services/SchoolYears/SchoolYearContextService.php @@ -9,7 +9,9 @@ use Illuminate\Support\Facades\Schema; class SchoolYearContextService { - public function __construct(private SchoolYearResolver $resolver) {} + public function __construct(private SchoolYearResolver $resolver) + { + } public function currentSchoolYear(?string $requested = null): string { @@ -93,7 +95,7 @@ class SchoolYearContextService } foreach ($this->legacySchoolYearNames() as $name) { - if (! isset($seen[$name])) { + if (!isset($seen[$name])) { $years[] = [ 'id' => null, 'name' => $name, @@ -109,7 +111,7 @@ class SchoolYearContextService } $include = trim((string) $include); - if ($include !== '' && ! isset($seen[$include])) { + if ($include !== '' && !isset($seen[$include])) { array_unshift($years, [ 'id' => null, 'name' => $include, @@ -129,7 +131,7 @@ class SchoolYearContextService { $names = ['Fall', 'Spring']; $current = trim((string) $include); - if ($current !== '' && ! in_array($current, $names, true)) { + if ($current !== '' && !in_array($current, $names, true)) { array_unshift($names, $current); } @@ -151,7 +153,7 @@ class SchoolYearContextService $names = []; foreach ($tables as $table) { - if (! Schema::hasTable($table) || ! Schema::hasColumn($table, 'school_year')) { + if (!Schema::hasTable($table) || !Schema::hasColumn($table, 'school_year')) { continue; } diff --git a/app/Services/SchoolYears/SchoolYearResolver.php b/app/Services/SchoolYears/SchoolYearResolver.php index 510d1f96..ffc07421 100644 --- a/app/Services/SchoolYears/SchoolYearResolver.php +++ b/app/Services/SchoolYears/SchoolYearResolver.php @@ -16,7 +16,7 @@ class SchoolYearResolver $existing = SchoolYear::query()->where('name', $current)->first(); if ($existing) { - if ($existing->status !== SchoolYear::STATUS_ACTIVE || ! $existing->is_current) { + if ($existing->status !== SchoolYear::STATUS_ACTIVE || !$existing->is_current) { SchoolYear::query()->where('id', '!=', $existing->id)->where('is_current', true)->update([ 'is_current' => false, 'updated_at' => now(), diff --git a/app/Services/SchoolYears/SchoolYearWriteGuard.php b/app/Services/SchoolYears/SchoolYearWriteGuard.php index cd86fafa..c44632d7 100644 --- a/app/Services/SchoolYears/SchoolYearWriteGuard.php +++ b/app/Services/SchoolYears/SchoolYearWriteGuard.php @@ -10,7 +10,7 @@ class SchoolYearWriteGuard { public function assertEditable(array $schoolYears): void { - if (! Schema::hasTable('school_years')) { + if (!Schema::hasTable('school_years')) { return; } diff --git a/app/Services/Scores/AttendanceCalculator.php b/app/Services/Scores/AttendanceCalculator.php index f5d45b20..f97b3120 100644 --- a/app/Services/Scores/AttendanceCalculator.php +++ b/app/Services/Scores/AttendanceCalculator.php @@ -14,7 +14,8 @@ class AttendanceCalculator implements ScoreCalculatorInterface private AttendanceRecord $attendanceModel, private Configuration $configModel, private CalendarEvent $calendarModel - ) {} + ) { + } public function calculate(int $studentId, string $semester, string $schoolYear, ?int $classSectionId = null): array { @@ -29,7 +30,7 @@ class AttendanceCalculator implements ScoreCalculatorInterface $events = CalendarEvent::getEventsBySchoolYearAndSemester($schoolYear, $normSemester); $noSchoolSundays = 0; foreach ($events as $event) { - if (! empty($event['no_school'])) { + if (!empty($event['no_school'])) { $date = new \DateTime($event['date']); if ($date->format('N') == 7) { if ($date->format('Y-m-d') >= $semRange[0] && $date->format('Y-m-d') <= $semRange[1]) { @@ -74,21 +75,16 @@ class AttendanceCalculator implements ScoreCalculatorInterface protected function normalizeSemester(?string $input): string { $s = strtolower(trim((string) $input)); - if ($s === 'fall' || str_contains($s, '1')) { - return 'fall'; - } - if ($s === 'spring' || str_contains($s, '2')) { - return 'spring'; - } - + if ($s === 'fall' || str_contains($s, '1')) return 'fall'; + if ($s === 'spring' || str_contains($s, '2')) return 'spring'; return ''; } protected function getSemesterRange(string $schoolYear, string $semester): ?array { $norm = $this->normalizeSemester($semester); - if ($norm === '' || ! preg_match('/^(\d{4})-(\d{4})$/', trim($schoolYear), $m)) { - if ($norm === '' || ! preg_match('/^(\d{4})/', trim($schoolYear), $m)) { + if ($norm === '' || !preg_match('/^(\d{4})-(\d{4})$/', trim($schoolYear), $m)) { + if ($norm === '' || !preg_match('/^(\d{4})/', trim($schoolYear), $m)) { return null; } $y1 = (int) $m[1]; @@ -106,14 +102,12 @@ class AttendanceCalculator implements ScoreCalculatorInterface if ($norm === 'fall') { $start = ($fallStartCfg !== '') ? sprintf('%04d-%s', $y1, date('m-d', strtotime($fallStartCfg))) : "{$y1}-09-01"; $end = ($fallEndCfg !== '') ? sprintf('%04d-%s', $y2, date('m-d', strtotime($fallEndCfg))) : "{$y2}-01-15"; - return [$start, $end]; } if ($norm === 'spring') { $start = ($springStartCfg !== '') ? sprintf('%04d-%s', $y2, date('m-d', strtotime($springStartCfg))) : "{$y2}-01-16"; $end = ($springEndCfg !== '') ? sprintf('%04d-%s', $y2, date('m-d', strtotime($springEndCfg))) : "{$y2}-06-30"; - return [$start, $end]; } @@ -133,7 +127,6 @@ class AttendanceCalculator implements ScoreCalculatorInterface $sundays++; } } - return $sundays; } @@ -146,12 +139,11 @@ class AttendanceCalculator implements ScoreCalculatorInterface $configKey = $norm === 'fall' ? 'total_semester1_days' : 'total_semester2_days'; $value = Configuration::getConfig($configKey); - if (! is_numeric($value)) { + if (!is_numeric($value)) { return null; } $length = (int) $value; - return $length > 0 ? $length : null; } } diff --git a/app/Services/Scores/ExamScoreService.php b/app/Services/Scores/ExamScoreService.php index f4b0a123..66746cda 100644 --- a/app/Services/Scores/ExamScoreService.php +++ b/app/Services/Scores/ExamScoreService.php @@ -2,17 +2,19 @@ namespace App\Services\Scores; -use App\Models\ClassSection; use App\Models\GradingLock; use App\Models\MissingScoreOverride; use App\Models\Student; use App\Models\TeacherClass; +use App\Models\ClassSection; use App\Services\Grading\Validation\ScoreValueValidator; use Illuminate\Support\Facades\DB; class ExamScoreService { - public function __construct(private ScoreTermService $term) {} + public function __construct(private ScoreTermService $term) + { + } public function resolveClassSectionIdForTeacher(int $teacherId, ?int $requestedClassSectionId, ?string $schoolYearInput): ?int { @@ -70,7 +72,7 @@ class ExamScoreService ->where('sc.school_year', '=', $schoolYear); }) ->leftJoinSub($latestSub, 'latest', 'latest.student_id', '=', 's.id') - ->leftJoin($table.' as ex', 'ex.id', '=', 'latest.max_id') + ->leftJoin($table . ' as ex', 'ex.id', '=', 'latest.max_id') ->orderBy('s.lastname') ->orderBy('s.firstname') ->get() @@ -123,17 +125,17 @@ class ExamScoreService $count = 0; foreach ($scores as $studentId => $data) { - if (! is_numeric($studentId)) { + if (!is_numeric($studentId)) { continue; } $student = Student::query()->find((int) $studentId); - if (! $student) { + if (!$student) { continue; } $rawScore = is_array($data) ? ($data['score'] ?? null) : $data; - $validator = new ScoreValueValidator; + $validator = new ScoreValueValidator(); $normalizedScore = $validator->normalizeNullable($rawScore, ScoreValueValidator::DEFAULT_MAX_POINTS, 'Exam score'); - $missingAllowed = ! empty($missingOk[$studentId]); + $missingAllowed = !empty($missingOk[$studentId]); $existing = $builder ->where('student_id', $studentId) @@ -176,7 +178,7 @@ class ExamScoreService $schoolYearVariants = [$schoolYear]; } - $rows = DB::table($table.' as ex') + $rows = DB::table($table . ' as ex') ->select([ 'ex.*', 's.firstname as student_firstname', diff --git a/app/Services/Scores/HomeworkCalculator.php b/app/Services/Scores/HomeworkCalculator.php index 18eabce4..96a63d1d 100644 --- a/app/Services/Scores/HomeworkCalculator.php +++ b/app/Services/Scores/HomeworkCalculator.php @@ -7,12 +7,13 @@ use App\Models\Homework; class HomeworkCalculator implements ScoreCalculatorInterface { - public function __construct(private Homework $homeworkModel) {} + public function __construct(private Homework $homeworkModel) + { + } public function calculate(int $studentId, string $semester, string $schoolYear, ?int $classSectionId = null): array { $average = Homework::getAverageHomeworkScore($studentId, $semester, $schoolYear, $classSectionId); - return ['homework_avg' => $average !== null ? (float) $average : null]; } } diff --git a/app/Services/Scores/HomeworkScoreService.php b/app/Services/Scores/HomeworkScoreService.php index 2c95a63e..13475f69 100644 --- a/app/Services/Scores/HomeworkScoreService.php +++ b/app/Services/Scores/HomeworkScoreService.php @@ -2,18 +2,20 @@ namespace App\Services\Scores; -use App\Models\ClassSection; use App\Models\GradingLock; use App\Models\Homework; use App\Models\MissingScoreOverride; use App\Models\Student; use App\Models\StudentClass; use App\Models\TeacherClass; +use App\Models\ClassSection; use App\Services\Grading\Validation\ScoreValueValidator; class HomeworkScoreService { - public function __construct(private ScoreTermService $term) {} + public function __construct(private ScoreTermService $term) + { + } /** * When the client omits class_section_id (legacy teacher portal), use the teacher's assignment @@ -172,7 +174,6 @@ class HomeworkScoreService return true; } } - return false; } @@ -180,11 +181,10 @@ class HomeworkScoreService { foreach ($schoolYearVariants as $year) { $map = MissingScoreOverride::getOverridesMap($classSectionId, $semester, $year, 'homework'); - if (! empty($map)) { + if (!empty($map)) { return $map; } } - return []; } @@ -197,7 +197,7 @@ class HomeworkScoreService $studentIds = array_keys($scores); $indexSet = []; foreach ($scores as $hwData) { - if (! is_array($hwData)) { + if (!is_array($hwData)) { continue; } foreach ($hwData as $index => $_) { @@ -209,11 +209,11 @@ class HomeworkScoreService $checkedItems = []; foreach ($missingOk as $studentId => $indexes) { - if (! is_array($indexes)) { + if (!is_array($indexes)) { continue; } foreach ($indexes as $index => $flag) { - if (! is_numeric($index)) { + if (!is_numeric($index)) { continue; } $checkedItems[] = [ @@ -236,22 +236,22 @@ class HomeworkScoreService $count = 0; foreach ($scores as $studentId => $hwData) { - if (! is_numeric($studentId) || ! is_array($hwData)) { + if (!is_numeric($studentId) || !is_array($hwData)) { continue; } $student = Student::query()->find((int) $studentId); - if (! $student) { + if (!$student) { continue; } foreach ($hwData as $index => $score) { - if (! is_numeric($index)) { + if (!is_numeric($index)) { continue; } $rawScore = $score ?? null; - $validator = new ScoreValueValidator; + $validator = new ScoreValueValidator(); $normalizedScore = $validator->normalizeNullable($rawScore, ScoreValueValidator::DEFAULT_MAX_POINTS, 'Homework score'); - $missingAllowed = ! empty($missingOk[$studentId][$index]); + $missingAllowed = !empty($missingOk[$studentId][$index]); $existing = Homework::query() ->where('student_id', $studentId) @@ -306,7 +306,7 @@ class HomeworkScoreService foreach ($students as $student) { $studentRow = Student::query()->find((int) $student->student_id); - if (! $studentRow) { + if (!$studentRow) { continue; } $exists = Homework::query() diff --git a/app/Services/Scores/ParticipationScoreService.php b/app/Services/Scores/ParticipationScoreService.php index 53ae406e..ebcbf743 100644 --- a/app/Services/Scores/ParticipationScoreService.php +++ b/app/Services/Scores/ParticipationScoreService.php @@ -2,18 +2,20 @@ namespace App\Services\Scores; -use App\Models\ClassSection; use App\Models\GradingLock; +use App\Models\ClassSection; +use App\Services\Grading\Validation\ScoreValueValidator; use App\Models\MissingScoreOverride; use App\Models\Participation; use App\Models\Student; use App\Models\StudentClass; use App\Models\TeacherClass; -use App\Services\Grading\Validation\ScoreValueValidator; class ParticipationScoreService { - public function __construct(private ScoreTermService $term) {} + public function __construct(private ScoreTermService $term) + { + } public function resolveClassSectionIdForTeacher(int $teacherId, ?int $requestedClassSectionId, ?string $schoolYearInput): ?int { @@ -171,22 +173,22 @@ class ParticipationScoreService $count = 0; foreach ($scores as $studentId => $data) { - if (! is_numeric($studentId)) { + if (!is_numeric($studentId)) { continue; } - if (! is_array($data)) { + if (!is_array($data)) { $data = ['score' => $data]; } $student = Student::query()->find((int) $studentId); - if (! $student) { + if (!$student) { continue; } $rawScore = $data['score'] ?? null; - $validator = new ScoreValueValidator; + $validator = new ScoreValueValidator(); $normalizedScore = $validator->normalizeNullable($rawScore, ScoreValueValidator::DEFAULT_MAX_POINTS, 'Participation score'); - $missingAllowed = ! empty($missingOk[$studentId]); + $missingAllowed = !empty($missingOk[$studentId]); $existing = Participation::query() ->where('student_id', $studentId) diff --git a/app/Services/Scores/ProjectCalculator.php b/app/Services/Scores/ProjectCalculator.php index 15cce2f3..b4c4da27 100644 --- a/app/Services/Scores/ProjectCalculator.php +++ b/app/Services/Scores/ProjectCalculator.php @@ -7,12 +7,13 @@ use App\Models\Project; class ProjectCalculator implements ScoreCalculatorInterface { - public function __construct(private Project $projectModel) {} + public function __construct(private Project $projectModel) + { + } public function calculate(int $studentId, string $semester, string $schoolYear, ?int $classSectionId = null): array { $average = Project::averageScore($studentId, $semester, $schoolYear, $classSectionId); - return ['project_avg' => $average !== null ? (float) $average : null]; } } diff --git a/app/Services/Scores/ProjectScoreService.php b/app/Services/Scores/ProjectScoreService.php index 43c2eaa0..6372d968 100644 --- a/app/Services/Scores/ProjectScoreService.php +++ b/app/Services/Scores/ProjectScoreService.php @@ -2,18 +2,21 @@ namespace App\Services\Scores; -use App\Models\ClassSection; use App\Models\GradingLock; use App\Models\MissingScoreOverride; use App\Models\Project; use App\Models\Student; use App\Models\StudentClass; use App\Models\TeacherClass; +use App\Models\ClassSection; use App\Services\Grading\Validation\ScoreValueValidator; +use Illuminate\Support\Facades\DB; class ProjectScoreService { - public function __construct(private ScoreTermService $term) {} + public function __construct(private ScoreTermService $term) + { + } public function resolveClassSectionIdForTeacher(int $teacherId, ?int $requestedClassSectionId, ?string $schoolYearInput): ?int { @@ -165,7 +168,7 @@ class ProjectScoreService $studentIds = array_keys($scores); $indexSet = []; foreach ($scores as $projects) { - if (! is_array($projects)) { + if (!is_array($projects)) { continue; } foreach ($projects as $index => $_) { @@ -177,11 +180,11 @@ class ProjectScoreService $checkedItems = []; foreach ($missingOk as $studentId => $indexes) { - if (! is_array($indexes)) { + if (!is_array($indexes)) { continue; } foreach ($indexes as $index => $flag) { - if (! is_numeric($index)) { + if (!is_numeric($index)) { continue; } $checkedItems[] = [ @@ -204,21 +207,21 @@ class ProjectScoreService $count = 0; foreach ($scores as $studentId => $projects) { - if (! is_numeric($studentId) || ! is_array($projects)) { + if (!is_numeric($studentId) || !is_array($projects)) { continue; } $student = Student::query()->find((int) $studentId); - if (! $student) { + if (!$student) { continue; } foreach ($projects as $index => $score) { - if (! is_numeric($index)) { + if (!is_numeric($index)) { continue; } - $validator = new ScoreValueValidator; + $validator = new ScoreValueValidator(); $normalizedScore = $validator->normalizeNullable($score, ScoreValueValidator::DEFAULT_MAX_POINTS, 'Project score'); - $missingAllowed = ! empty($missingOk[$studentId][$index]); + $missingAllowed = !empty($missingOk[$studentId][$index]); $existing = Project::query() ->where('student_id', $studentId) @@ -272,7 +275,7 @@ class ProjectScoreService foreach ($students as $student) { $studentRow = Student::query()->find((int) $student->student_id); - if (! $studentRow) { + if (!$studentRow) { continue; } $exists = Project::query() diff --git a/app/Services/Scores/QuizCalculator.php b/app/Services/Scores/QuizCalculator.php index 03468d3e..63708f75 100644 --- a/app/Services/Scores/QuizCalculator.php +++ b/app/Services/Scores/QuizCalculator.php @@ -24,7 +24,7 @@ class QuizCalculator implements ScoreCalculatorInterface $count = 0; foreach ($rows as $row) { $score = $row->score ?? null; - if ($score === null || $score === '' || ! is_numeric($score)) { + if ($score === null || $score === '' || !is_numeric($score)) { continue; } $total += (float) $score; diff --git a/app/Services/Scores/QuizScoreService.php b/app/Services/Scores/QuizScoreService.php index 72c52c25..117ede14 100644 --- a/app/Services/Scores/QuizScoreService.php +++ b/app/Services/Scores/QuizScoreService.php @@ -2,18 +2,20 @@ namespace App\Services\Scores; -use App\Models\ClassSection; use App\Models\GradingLock; use App\Models\MissingScoreOverride; use App\Models\Quiz; use App\Models\Student; use App\Models\StudentClass; use App\Models\TeacherClass; +use App\Models\ClassSection; use App\Services\Grading\Validation\ScoreValueValidator; class QuizScoreService { - public function __construct(private ScoreTermService $term) {} + public function __construct(private ScoreTermService $term) + { + } public function resolveClassSectionIdForTeacher(int $teacherId, ?int $requestedClassSectionId, ?string $schoolYearInput): ?int { @@ -165,7 +167,7 @@ class QuizScoreService $studentIds = array_keys($scores); $indexSet = []; foreach ($scores as $quizData) { - if (! is_array($quizData)) { + if (!is_array($quizData)) { continue; } foreach ($quizData as $index => $_) { @@ -177,11 +179,11 @@ class QuizScoreService $checkedItems = []; foreach ($missingOk as $studentId => $indexes) { - if (! is_array($indexes)) { + if (!is_array($indexes)) { continue; } foreach ($indexes as $index => $flag) { - if (! is_numeric($index)) { + if (!is_numeric($index)) { continue; } $checkedItems[] = [ @@ -204,23 +206,23 @@ class QuizScoreService $count = 0; foreach ($scores as $studentId => $quizData) { - if (! is_numeric($studentId)) { + if (!is_numeric($studentId)) { continue; } - if (! is_array($quizData)) { + if (!is_array($quizData)) { $quizData = [1 => $quizData]; } $student = Student::query()->find((int) $studentId); - if (! $student) { + if (!$student) { continue; } foreach ($quizData as $quizNumber => $score) { - if (! is_numeric($quizNumber)) { + if (!is_numeric($quizNumber)) { continue; } - $validator = new ScoreValueValidator; + $validator = new ScoreValueValidator(); $normalizedScore = $validator->normalizeNullable($score, ScoreValueValidator::DEFAULT_MAX_POINTS, 'Quiz score'); - $missingAllowed = ! empty($missingOk[$studentId][$quizNumber]); + $missingAllowed = !empty($missingOk[$studentId][$quizNumber]); $existing = Quiz::query() ->where('student_id', $studentId) @@ -274,7 +276,7 @@ class QuizScoreService foreach ($students as $student) { $studentRow = Student::query()->find((int) $student->student_id); - if (! $studentRow) { + if (!$studentRow) { continue; } $exists = Quiz::query() diff --git a/app/Services/Scores/ScoreCommentService.php b/app/Services/Scores/ScoreCommentService.php index b316b943..6796f64c 100644 --- a/app/Services/Scores/ScoreCommentService.php +++ b/app/Services/Scores/ScoreCommentService.php @@ -2,18 +2,21 @@ namespace App\Services\Scores; -use App\Models\ClassSection; use App\Models\Configuration; +use App\Models\ClassSection; use App\Models\GradingLock; use App\Models\MissingScoreOverride; use App\Models\ScoreComment; use App\Models\SemesterScore; use App\Models\Student; +use App\Models\StudentClass; use Illuminate\Support\Facades\DB; class ScoreCommentService { - public function __construct(private ScoreTermService $term) {} + public function __construct(private ScoreTermService $term) + { + } public function list(?string $classSectionId, ?string $semester, ?string $schoolYear): array { @@ -30,24 +33,24 @@ class ScoreCommentService ->orderBy('s.firstname') ->distinct(); - if (! $isAllSections && $classSectionInt) { + if (!$isAllSections && $classSectionInt) { $builder->where('sc.class_section_id', $classSectionInt); } $students = $builder->get()->map(fn ($row) => (array) $row)->all(); $comments = []; - if (! empty($students)) { + if (!empty($students)) { $studentIds = array_map(static fn ($r) => (int) $r['student_id'], $students); $rawComments = ScoreComment::query() ->whereIn('student_id', $studentIds) ->whereIn('score_type', ['midterm', 'final', 'ptap', 'attendance']) ->where('semester', $activeSemester) ->where('school_year', $schoolYear) - ->when(! $isAllSections && $classSectionInt, function ($q) use ($classSectionInt) { + ->when(!$isAllSections && $classSectionInt, function ($q) use ($classSectionInt) { $q->where(function ($w) use ($classSectionInt) { $w->where('class_section_id', $classSectionInt) - ->orWhereNull('class_section_id'); + ->orWhereNull('class_section_id'); }); }) ->get(); @@ -84,7 +87,7 @@ class ScoreCommentService if ($hasComment) { continue; } - if (! function_exists('attendance_comment_from_score')) { + if (!function_exists('attendance_comment_from_score')) { continue; } $score = $attendanceScores[$sid] ?? null; @@ -109,10 +112,10 @@ class ScoreCommentService 'semester' => $activeSemester, 'schoolYear' => $schoolYear, 'classSectionId' => $isAllSections ? 'allsections' : $classSectionInt, - 'classSectionName' => (! $isAllSections && $classSectionInt) + 'classSectionName' => (!$isAllSections && $classSectionInt) ? (string) (ClassSection::query()->where('class_section_id', $classSectionInt)->value('class_section_name') ?? '') : '', - 'scoresLocked' => (! $isAllSections && $classSectionInt) + 'scoresLocked' => (!$isAllSections && $classSectionInt) ? GradingLock::isLocked($classSectionInt, $activeSemester, $schoolYear) : false, ]; @@ -140,7 +143,7 @@ class ScoreCommentService foreach ($commentTypes as $type) { $checkedItems = []; foreach ($missingOk as $studentId => $types) { - if (! is_array($types) || empty($types[$type])) { + if (!is_array($types) || empty($types[$type])) { continue; } $checkedItems[] = [ @@ -172,7 +175,6 @@ class ScoreCommentService $validationError = $this->validateComment($trimmedComment, (int) $studentId, $normalizedScoreType, $studentNames); if ($validationError !== null) { $errors[] = $validationError; - continue; } @@ -183,7 +185,7 @@ class ScoreCommentService ->where('school_year', $schoolYear) ->where(function ($q) use ($classSectionId) { $q->where('class_section_id', $classSectionId) - ->orWhereNull('class_section_id'); + ->orWhereNull('class_section_id'); }) ->first(); @@ -237,7 +239,6 @@ class ScoreCommentService $validationError = $this->validateComment($commentText, (int) $studentId, $normalizedScoreType, $studentNames); if ($validationError !== null) { $errors[] = $validationError; - continue; } } @@ -249,7 +250,7 @@ class ScoreCommentService ->where('school_year', $schoolYear) ->where(function ($q) use ($classSectionId) { $q->where('class_section_id', $classSectionId) - ->orWhereNull('class_section_id'); + ->orWhereNull('class_section_id'); }) ->first(); @@ -321,8 +322,8 @@ class ScoreCommentService return "{$firstName}'s {$scoreType} comment must be at most 400 characters."; } - $pattern = '/^'.preg_quote($firstName, '/').'\\b/i'; - if (! preg_match($pattern, $trimmed)) { + $pattern = '/^' . preg_quote($firstName, '/') . '\\b/i'; + if (!preg_match($pattern, $trimmed)) { return "{$firstName}'s {$scoreType} comment must start with the student's first name."; } @@ -332,7 +333,7 @@ class ScoreCommentService private function isReviewer(): bool { $user = auth()->user(); - if (! $user) { + if (!$user) { return false; } @@ -353,6 +354,6 @@ class ScoreCommentService explode(',', $reviewerRoles) ); - return ! empty(array_intersect($currentUserRoles, $allowedRoles)); + return !empty(array_intersect($currentUserRoles, $allowedRoles)); } } diff --git a/app/Services/Scores/ScoreDashboardService.php b/app/Services/Scores/ScoreDashboardService.php index cbe417e4..fe4546ce 100644 --- a/app/Services/Scores/ScoreDashboardService.php +++ b/app/Services/Scores/ScoreDashboardService.php @@ -3,6 +3,7 @@ namespace App\Services\Scores; use App\Models\ClassSection; +use App\Models\Configuration; use App\Models\GradingLock; use App\Models\MissingScoreOverride; use App\Models\ScoreComment; @@ -14,14 +15,16 @@ use Illuminate\Support\Facades\DB; class ScoreDashboardService { - public function __construct(private ScoreTermService $term) {} + public function __construct(private ScoreTermService $term) + { + } public function overview(int $teacherId, ?int $classSectionId, ?string $semester, ?string $schoolYear): array { $schoolYear = $this->term->schoolYear($schoolYear); $semesterLabel = $this->term->semesterLabel($semester, $semester); - if ($teacherId <= 0 && ! empty($classSectionId)) { + if ($teacherId <= 0 && !empty($classSectionId)) { $allowedIds = [(int) $classSectionId]; } else { $allowedIds = TeacherClass::query() @@ -42,7 +45,7 @@ class ScoreDashboardService $studentQuery = StudentClass::query(); if (DB::connection()->getDriverName() === 'sqlite') { - $studentQuery->whereRaw('class_section_id = '.(int) $classSectionId); + $studentQuery->whereRaw('class_section_id = ' . (int) $classSectionId); if ($schoolYear !== '') { $quoted = DB::connection()->getPdo()->quote($schoolYear); $studentQuery->whereRaw("school_year = {$quoted}"); @@ -59,9 +62,9 @@ class ScoreDashboardService ->map(fn ($v) => (int) $v) ->all(); if (empty($studentIds) && DB::connection()->getDriverName() === 'sqlite') { - $schoolYearClause = $schoolYear !== '' ? ' and school_year = '.DB::connection()->getPdo()->quote($schoolYear) : ''; + $schoolYearClause = $schoolYear !== '' ? " and school_year = " . DB::connection()->getPdo()->quote($schoolYear) : ''; $rows = DB::select( - 'select student_id from student_class where class_section_id = '.(int) $classSectionId.$schoolYearClause + "select student_id from student_class where class_section_id = " . (int) $classSectionId . $schoolYearClause ); $studentIds = array_values(array_filter(array_map( static fn ($row) => isset($row->student_id) ? (int) $row->student_id : 0, @@ -170,7 +173,7 @@ class ScoreDashboardService foreach ($commentTypes as $type) { $checkedItems = []; foreach ($missingOk as $studentId => $types) { - if (! is_array($types) || empty($types[$type])) { + if (!is_array($types) || empty($types[$type])) { continue; } $checkedItems[] = [ @@ -226,7 +229,7 @@ class ScoreDashboardService ->all(); $scores = []; - if (! empty($students)) { + if (!empty($students)) { $studentIdList = array_column($students, 'id'); $semesterScores = DB::table('semester_scores') ->whereIn('student_id', $studentIdList) diff --git a/app/Services/Scores/ScorePredictorDataService.php b/app/Services/Scores/ScorePredictorDataService.php index 04716959..66da63b8 100644 --- a/app/Services/Scores/ScorePredictorDataService.php +++ b/app/Services/Scores/ScorePredictorDataService.php @@ -56,7 +56,7 @@ class ScorePredictorDataService ->orWhere('cs.class_section_name', 'not like', 'KG%'); }); - if (! empty($classSectionId)) { + if (!empty($classSectionId)) { $builder->where('sc.class_section_id', $classSectionId); } @@ -81,7 +81,7 @@ class ScorePredictorDataService ->orWhere('cs.class_section_name', 'not like', 'KG%'); }); - if (! empty($classSectionId)) { + if (!empty($classSectionId)) { $builder->where('student_class.class_section_id', $classSectionId); } diff --git a/app/Services/Scores/ScorePredictorRiskService.php b/app/Services/Scores/ScorePredictorRiskService.php index 46382f0b..cbb9ad1b 100644 --- a/app/Services/Scores/ScorePredictorRiskService.php +++ b/app/Services/Scores/ScorePredictorRiskService.php @@ -14,7 +14,6 @@ class ScorePredictorRiskService $a5 = 1.061405429; $erf = 1 - ((((($a5 * $t + $a4) * $t + $a3) * $t + $a2) * $t + $a1) * $t) * exp(-$z * $z); $sign = $z < 0 ? -1 : 1; - return 0.5 * (1 + $sign * $erf); } @@ -27,7 +26,7 @@ class ScorePredictorRiskService $springScore = is_numeric($student['spring_score'] ?? null) ? (float) $student['spring_score'] : null; $scoreParts = array_values(array_filter([$fallScore, $springScore], static fn ($v) => $v !== null)); - $finalAvg = ! empty($scoreParts) ? round(array_sum($scoreParts) / count($scoreParts), 1) : null; + $finalAvg = !empty($scoreParts) ? round(array_sum($scoreParts) / count($scoreParts), 1) : null; $waitingForSpring = ($fallScore !== null && $springScore === null); @@ -41,8 +40,8 @@ class ScorePredictorRiskService $probLow = $zLow !== null ? $this->normalCdf($zLow) : null; $riskHigh = match (true) { - $finalAvg !== null && ! $waitingForSpring && $finalAvg >= $trophyThreshold => 'Achieved Trophy', - $finalAvg !== null && ! $waitingForSpring => 'Unreachable', + $finalAvg !== null && !$waitingForSpring && $finalAvg >= $trophyThreshold => 'Achieved Trophy', + $finalAvg !== null && !$waitingForSpring => 'Unreachable', $requiredHigh !== null && $requiredHigh > 100 => 'Unreachable', is_null($probHigh) => 'New student', $probHigh >= 0.66 => 'Low', @@ -51,8 +50,8 @@ class ScorePredictorRiskService }; $riskLow = match (true) { - $finalAvg !== null && ! $waitingForSpring && $finalAvg < $targetLow => 'High', - $finalAvg !== null && ! $waitingForSpring => 'Low', + $finalAvg !== null && !$waitingForSpring && $finalAvg < $targetLow => 'High', + $finalAvg !== null && !$waitingForSpring => 'Low', $requiredLow !== null && $requiredLow > 100 => 'Unlikely to pass', is_null($probLow) => 'New student', $probLow >= 0.66 => 'High', @@ -104,23 +103,19 @@ class ScorePredictorRiskService } foreach ($bySection as $cid => $indices) { - if (! empty($hasThresholdTrophy[$cid])) { + if (!empty($hasThresholdTrophy[$cid])) { continue; } $candidates = []; foreach ($indices as $idx) { $val = $results[$idx]['final_average'] ?? null; - if (! is_numeric($val)) { + if (!is_numeric($val)) { $fall = $results[$idx]['fall_score'] ?? null; $spring = $results[$idx]['spring_score'] ?? null; $parts = []; - if (is_numeric($fall)) { - $parts[] = (float) $fall; - } - if (is_numeric($spring)) { - $parts[] = (float) $spring; - } - if (! empty($parts)) { + if (is_numeric($fall)) $parts[] = (float) $fall; + if (is_numeric($spring)) $parts[] = (float) $spring; + if (!empty($parts)) { $val = array_sum($parts) / count($parts); } } diff --git a/app/Services/Scores/ScorePredictorService.php b/app/Services/Scores/ScorePredictorService.php index 7e860ab1..5f37be9f 100644 --- a/app/Services/Scores/ScorePredictorService.php +++ b/app/Services/Scores/ScorePredictorService.php @@ -9,7 +9,8 @@ class ScorePredictorService public function __construct( private ScorePredictorDataService $dataService, private ScorePredictorRiskService $riskService - ) {} + ) { + } public function report(?string $schoolYear, ?int $classSectionId = null): array { diff --git a/app/Services/Scores/ScoreTermService.php b/app/Services/Scores/ScoreTermService.php index f9cbf145..1ab6eb47 100644 --- a/app/Services/Scores/ScoreTermService.php +++ b/app/Services/Scores/ScoreTermService.php @@ -15,7 +15,6 @@ class ScoreTermService if ($value === 'spring' || str_contains($value, '2')) { return 'spring'; } - return ''; } diff --git a/app/Services/Scores/SemesterScoreService.php b/app/Services/Scores/SemesterScoreService.php index 978e45ae..5bd082f8 100644 --- a/app/Services/Scores/SemesterScoreService.php +++ b/app/Services/Scores/SemesterScoreService.php @@ -3,17 +3,21 @@ namespace App\Services\Scores; use App\Interfaces\ScoreCalculatorInterface; -use App\Models\AttendanceRecord; -use App\Models\CalendarEvent; use App\Models\Configuration; use App\Models\FinalExam; -use App\Models\Homework; use App\Models\MidtermExam; use App\Models\Participation; -use App\Models\Project; use App\Models\SemesterScore; -use App\Services\Grading\Policy\GradingPolicyResolver; +use App\Services\Scores\AttendanceCalculator; +use App\Services\Scores\HomeworkCalculator; +use App\Services\Scores\ProjectCalculator; +use App\Services\Scores\QuizCalculator; +use App\Models\AttendanceRecord; +use App\Models\CalendarEvent; +use App\Models\Homework; +use App\Models\Project; use RuntimeException; +use App\Services\Grading\Policy\GradingPolicyResolver; class SemesterScoreService { @@ -21,11 +25,8 @@ class SemesterScoreService private array $scoreCalculators = []; private string $semester; - private string $schoolYear; - private ?int $actorId; - private GradingPolicyResolver $policyResolver; public function __construct( @@ -37,16 +38,16 @@ class SemesterScoreService $this->semester = (string) (Configuration::getConfig('semester') ?? ''); $this->schoolYear = (string) (Configuration::getConfig('school_year') ?? ''); $this->actorId = (int) (auth()->id() ?? 0) ?: null; - $this->policyResolver = new GradingPolicyResolver; + $this->policyResolver = new GradingPolicyResolver(); $attendanceCalculator = $attendanceCalculator ?? new AttendanceCalculator( - new AttendanceRecord, - new Configuration, - new CalendarEvent + new AttendanceRecord(), + new Configuration(), + new CalendarEvent() ); - $homeworkCalculator = $homeworkCalculator ?? new HomeworkCalculator(new Homework); - $quizCalculator = $quizCalculator ?? new QuizCalculator; - $projectCalculator = $projectCalculator ?? new ProjectCalculator(new Project); + $homeworkCalculator = $homeworkCalculator ?? new HomeworkCalculator(new Homework()); + $quizCalculator = $quizCalculator ?? new QuizCalculator(); + $projectCalculator = $projectCalculator ?? new ProjectCalculator(new Project()); $this->scoreCalculators = [ AttendanceCalculator::class => $attendanceCalculator, @@ -69,7 +70,7 @@ class SemesterScoreService public function updateStudentScores(array $student, string $semester, string $schoolYear): void { foreach (['student_id', 'school_id', 'class_section_id'] as $field) { - if (! isset($student[$field])) { + if (!isset($student[$field])) { throw new RuntimeException("Missing required student field: {$field}"); } } @@ -113,7 +114,7 @@ class SemesterScoreService } } - if (! isset($scoreData['participation_score'])) { + if (!isset($scoreData['participation_score'])) { $participationScore = Participation::getParticipationScore($studentId, $semester, $schoolYear, $classSectionId); $scoreData['participation_score'] = $participationScore !== null ? (float) $participationScore : null; } @@ -139,27 +140,24 @@ class SemesterScoreService $hasTests = $avgQuiz !== null; $hasProjects = $avgProject !== null; - if (! $hasTests && ! $hasProjects) { + if (!$hasTests && !$hasProjects) { if ($avgHomework === null || $avgParticipation === null) { return null; } - return round(($avgHomework * 0.5) + ($avgParticipation * 0.5), 1); } - if (! $hasProjects) { + if (!$hasProjects) { if ($avgHomework === null || $avgParticipation === null || $avgQuiz === null) { return null; } - return round(($avgHomework * 0.4) + ($avgParticipation * 0.4) + ($avgQuiz * 0.2), 1); } - if (! $hasTests) { + if (!$hasTests) { if ($avgHomework === null || $avgParticipation === null || $avgProject === null) { return null; } - return round(($avgHomework * 0.34) + ($avgParticipation * 0.33) + ($avgProject * 0.33), 1); } @@ -190,7 +188,6 @@ class SemesterScoreService if ($ptap !== null && $attendance !== null && $out['midterm_score'] !== null) { $out['semester_score'] = round(($attendance * 0.2) + ($ptap * 0.2) + ($out['midterm_score'] * 0.6), 1); } - return $out; } @@ -200,7 +197,6 @@ class SemesterScoreService if ($ptap !== null && $attendance !== null && $out['final_score'] !== null) { $out['semester_score'] = round(($attendance * 0.2) + ($ptap * 0.2) + ($out['final_score'] * 0.6), 1); } - return $out; } diff --git a/app/Services/Security/IpBanCommandService.php b/app/Services/Security/IpBanCommandService.php index 5a237752..26b92a0f 100644 --- a/app/Services/Security/IpBanCommandService.php +++ b/app/Services/Security/IpBanCommandService.php @@ -10,7 +10,7 @@ class IpBanCommandService public function banNow(?int $id, ?string $ip, int $hours): ?IpAttempt { $row = $this->findRow($id, $ip); - if (! $row) { + if (!$row) { return null; } @@ -21,7 +21,6 @@ class IpBanCommandService $row->blocked_until = $blockedUntil; $row->attempts = $attempts; $row->save(); - return $row->refresh(); }); } @@ -29,7 +28,7 @@ class IpBanCommandService public function unbanOne(?int $id, ?string $ip): ?IpAttempt { $row = $this->findRow($id, $ip); - if (! $row) { + if (!$row) { return null; } @@ -37,7 +36,6 @@ class IpBanCommandService $row->blocked_until = null; $row->attempts = 0; $row->save(); - return $row->refresh(); }); } @@ -69,7 +67,6 @@ class IpBanCommandService if (function_exists('utc_now')) { return (string) utc_now(); } - return now('UTC')->toDateTimeString(); } @@ -79,7 +76,6 @@ class IpBanCommandService if (function_exists('utc_now')) { return (string) date('Y-m-d H:i:s', strtotime("+{$hours} hours", strtotime((string) utc_now()))); } - return now('UTC')->addHours($hours)->toDateTimeString(); } } diff --git a/app/Services/Security/IpBanQueryService.php b/app/Services/Security/IpBanQueryService.php index 4de54ef5..d3468abb 100644 --- a/app/Services/Security/IpBanQueryService.php +++ b/app/Services/Security/IpBanQueryService.php @@ -16,8 +16,8 @@ class IpBanQueryService $query->where('blocked_until', '>', $this->utcNow()); } - if (! empty($filters['search'])) { - $term = '%'.trim((string) $filters['search']).'%'; + if (!empty($filters['search'])) { + $term = '%' . trim((string) $filters['search']) . '%'; $query->where('ip_address', 'like', $term); } @@ -41,7 +41,6 @@ class IpBanQueryService if (function_exists('utc_now')) { return (string) utc_now(); } - return now('UTC')->toDateTimeString(); } } diff --git a/app/Services/SemesterRangeService.php b/app/Services/SemesterRangeService.php index e9dec0d5..f13d68a3 100644 --- a/app/Services/SemesterRangeService.php +++ b/app/Services/SemesterRangeService.php @@ -7,7 +7,9 @@ use DateTimeImmutable; class SemesterRangeService { - public function __construct(private SemesterConfigService $configService) {} + public function __construct(private SemesterConfigService $configService) + { + } public function getSchoolYearRange(string $schoolYear): array { @@ -29,7 +31,7 @@ class SemesterRangeService public function getSemesterRange(string $schoolYear, string $semester): ?array { - if (! preg_match('/^(\\d{4})-(\\d{4})$/', $schoolYear, $m)) { + if (!preg_match('/^(\\d{4})-(\\d{4})$/', $schoolYear, $m)) { return null; } $y1 = (int) $m[1]; @@ -55,7 +57,6 @@ class SemesterRangeService if ($value === 'spring') { return 'Spring'; } - return ''; } @@ -102,15 +103,13 @@ class SemesterRangeService if (preg_match('/^(\\d{4})-(\\d{4})$/', $schoolYear, $m)) { $y1 = (int) $m[1]; $y2 = (int) $m[2]; - - return [new DateTimeImmutable($y1.'-09-01'), new DateTimeImmutable($y2.'-06-30')]; + return [new DateTimeImmutable($y1 . '-09-01'), new DateTimeImmutable($y2 . '-06-30')]; } $currentYear = (int) date('Y'); - return [ - new DateTimeImmutable($currentYear.'-09-01'), - new DateTimeImmutable(($currentYear + 1).'-06-30'), + new DateTimeImmutable($currentYear . '-09-01'), + new DateTimeImmutable(($currentYear + 1) . '-06-30'), ]; } } diff --git a/app/Services/Settings/ConfigurationService.php b/app/Services/Settings/ConfigurationService.php index 966b0523..fe1030db 100644 --- a/app/Services/Settings/ConfigurationService.php +++ b/app/Services/Settings/ConfigurationService.php @@ -25,7 +25,7 @@ class ConfigurationService public function update(int $id, array $payload): ?Configuration { $config = Configuration::query()->find($id); - if (! $config) { + if (!$config) { return null; } @@ -40,7 +40,7 @@ class ConfigurationService public function delete(int $id): bool { $config = Configuration::query()->find($id); - if (! $config) { + if (!$config) { return false; } diff --git a/app/Services/Settings/SchoolCalendar/SchoolCalendarFormatterService.php b/app/Services/Settings/SchoolCalendar/SchoolCalendarFormatterService.php index b0b62602..c75ab131 100644 --- a/app/Services/Settings/SchoolCalendar/SchoolCalendarFormatterService.php +++ b/app/Services/Settings/SchoolCalendar/SchoolCalendarFormatterService.php @@ -101,28 +101,28 @@ class SchoolCalendarFormatterService $parentName = (string) ($row['parent_name'] ?? 'Parent'); $studentName = (string) ($row['student_name'] ?? 'Student'); $time = trim((string) ($row['time'] ?? '')); - $timeLabel = $time !== '' ? (' '.$time) : ''; + $timeLabel = $time !== '' ? (' ' . $time) : ''; $title = $audience === 'admin' ? 'Admin Meeting' : 'Parent Meeting'; $descParts = []; - $descParts[] = 'Student: '.$studentName; - $descParts[] = 'Parent: '.$parentName; - if (! empty($row['class_section_name'])) { - $descParts[] = 'Section: '.$row['class_section_name']; + $descParts[] = 'Student: ' . $studentName; + $descParts[] = 'Parent: ' . $parentName; + if (!empty($row['class_section_name'])) { + $descParts[] = 'Section: ' . $row['class_section_name']; } - $descParts[] = 'Date/Time: '.($row['date'] ?? '').$timeLabel; - if (! empty($row['notes'])) { - $descParts[] = 'Notes: '.$row['notes']; + $descParts[] = 'Date/Time: ' . ($row['date'] ?? '') . $timeLabel; + if (!empty($row['notes'])) { + $descParts[] = 'Notes: ' . $row['notes']; } $start = (string) ($row['date'] ?? ''); if ($start !== '' && $time !== '') { - $start = $start.'T'.$time; + $start = $start . 'T' . $time; } return [ - 'id' => 'pm-'.(int) ($row['id'] ?? 0), + 'id' => 'pm-' . (int) ($row['id'] ?? 0), 'title' => $title, 'start' => $start, 'description' => implode("\n", $descParts), diff --git a/app/Services/Settings/SchoolCalendar/SchoolCalendarMeetingService.php b/app/Services/Settings/SchoolCalendar/SchoolCalendarMeetingService.php index 79c7e016..f05032d6 100644 --- a/app/Services/Settings/SchoolCalendar/SchoolCalendarMeetingService.php +++ b/app/Services/Settings/SchoolCalendar/SchoolCalendarMeetingService.php @@ -23,7 +23,7 @@ class SchoolCalendarMeetingService if ($audience === 'parent' && $parentUserId) { $studentIds = $this->getStudentIdsForParent($parentUserId); - if (! empty($studentIds)) { + if (!empty($studentIds)) { $builder->where(function (Builder $q) use ($parentUserId, $studentIds) { $q->where('parent_user_id', $parentUserId) ->orWhereIn('student_id', $studentIds); @@ -34,7 +34,7 @@ class SchoolCalendarMeetingService } $rows = $builder->orderBy('date', 'ASC')->get()->toArray(); - if (! empty($rows)) { + if (!empty($rows)) { return $rows; } @@ -48,7 +48,7 @@ class SchoolCalendarMeetingService if ($audience === 'parent' && $parentUserId) { $studentIds = $this->getStudentIdsForParent($parentUserId); - if (! empty($studentIds)) { + if (!empty($studentIds)) { $fallback->where(function (Builder $q) use ($parentUserId, $studentIds) { $q->where('parent_user_id', $parentUserId) ->orWhereIn('student_id', $studentIds); diff --git a/app/Services/Settings/SchoolCalendar/SchoolCalendarMutationService.php b/app/Services/Settings/SchoolCalendar/SchoolCalendarMutationService.php index faed63ea..a14861e1 100644 --- a/app/Services/Settings/SchoolCalendar/SchoolCalendarMutationService.php +++ b/app/Services/Settings/SchoolCalendar/SchoolCalendarMutationService.php @@ -11,7 +11,8 @@ class SchoolCalendarMutationService public function __construct( private SchoolCalendarContextService $context, private SchoolCalendarNotificationService $notificationService - ) {} + ) { + } public function create(array $payload, array $targets = []): array { @@ -22,7 +23,7 @@ class SchoolCalendarMutationService return CalendarEvent::query()->create($data); }); } catch (\Throwable $e) { - Log::error('SchoolCalendar create failed: '.$e->getMessage()); + Log::error('SchoolCalendar create failed: ' . $e->getMessage()); throw $e; } @@ -44,7 +45,7 @@ class SchoolCalendarMutationService $event->save(); }); } catch (\Throwable $e) { - Log::error('SchoolCalendar update failed: '.$e->getMessage()); + Log::error('SchoolCalendar update failed: ' . $e->getMessage()); throw $e; } @@ -64,7 +65,7 @@ class SchoolCalendarMutationService $event->delete(); }); } catch (\Throwable $e) { - Log::error('SchoolCalendar delete failed: '.$e->getMessage()); + Log::error('SchoolCalendar delete failed: ' . $e->getMessage()); throw $e; } } @@ -76,15 +77,15 @@ class SchoolCalendarMutationService 'description' => $payload['description'] ?? null, 'event_type' => $payload['event_type'] ?? null, 'date' => $payload['date'] ?? $payload['start'] ?? null, - 'notify_parent' => ! empty($payload['notify_parent']) ? 1 : 0, - 'notify_teacher' => ! empty($payload['notify_teacher']) ? 1 : 0, - 'notify_admin' => ! empty($payload['notify_admin']) ? 1 : 0, - 'no_school' => ! empty($payload['no_school']) ? 1 : 0, + 'notify_parent' => !empty($payload['notify_parent']) ? 1 : 0, + 'notify_teacher' => !empty($payload['notify_teacher']) ? 1 : 0, + 'notify_admin' => !empty($payload['notify_admin']) ? 1 : 0, + 'no_school' => !empty($payload['no_school']) ? 1 : 0, 'school_year' => $payload['school_year'] ?? $this->context->defaultSchoolYear(), 'semester' => $payload['semester'] ?? $this->context->defaultSemester(), ]; - if (! CalendarEvent::supportsEventType()) { + if (!CalendarEvent::supportsEventType()) { unset($data['event_type']); } diff --git a/app/Services/Settings/SchoolCalendar/SchoolCalendarNotificationService.php b/app/Services/Settings/SchoolCalendar/SchoolCalendarNotificationService.php index a62ae428..d51eba72 100644 --- a/app/Services/Settings/SchoolCalendar/SchoolCalendarNotificationService.php +++ b/app/Services/Settings/SchoolCalendar/SchoolCalendarNotificationService.php @@ -13,7 +13,8 @@ class SchoolCalendarNotificationService public function __construct( private EmailService $emailService, private ApplicationUrlService $urls, - ) {} + ) { + } public function notify(array $event, array $targets): array { @@ -26,7 +27,7 @@ class SchoolCalendarNotificationService $results = []; foreach ($targets as $group => $enabled) { - if (! $enabled) { + if (!$enabled) { continue; } @@ -34,13 +35,12 @@ class SchoolCalendarNotificationService if (empty($emails)) { Log::warning("SchoolCalendar: no recipient emails for {$group}."); $results[$group] = null; - continue; } $to = $emails[0] ?? ''; $ok = $this->emailService->send($to, $subject, $body, 'general', [], $emails); - if (! $ok) { + if (!$ok) { Log::warning("SchoolCalendar: failed to send calendar notification to {$group}."); } $results[$group] = $ok; @@ -52,9 +52,8 @@ class SchoolCalendarNotificationService private function buildSubject(array $event): string { $title = trim((string) ($event['title'] ?? 'School Calendar Update')); - $typeSegment = ! empty($event['event_type']) ? ' ('.$event['event_type'].')' : ''; - - return 'School Calendar: '.$title.$typeSegment; + $typeSegment = !empty($event['event_type']) ? ' (' . $event['event_type'] . ')' : ''; + return 'School Calendar: ' . $title . $typeSegment; } private function buildBody(array $event): string @@ -64,12 +63,12 @@ class SchoolCalendarNotificationService $date = (string) ($event['date'] ?? ''); $description = trim((string) ($event['description'] ?? '')); - $body = '

'.e($title).'

'; - $body .= '

Date: '.e($date).'

'; + $body = '

' . e($title) . '

'; + $body .= '

Date: ' . e($date) . '

'; if ($description !== '') { - $body .= '

'.nl2br(e($description)).'

'; + $body .= '

' . nl2br(e($description)) . '

'; } - $body .= '

View calendar

'; + $body .= '

View calendar

'; return $body; } @@ -89,19 +88,18 @@ class SchoolCalendarNotificationService $emails = []; foreach ($rows as $row) { $email = trim((string) ($row['email'] ?? '')); - if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL)) { + if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) { continue; } $emails[$email] = true; } - return array_values(array_keys($emails)); } private function fetchAdminRows(): array { $excluded = ['guest', 'teacher', 'teacher_assistant', 'parent']; - $escaped = array_map(static fn ($value) => "'".addslashes($value)."'", $excluded); + $escaped = array_map(static fn ($value) => "'" . addslashes($value) . "'", $excluded); $excludedList = implode(', ', $escaped); $builder = DB::table('users as u') diff --git a/app/Services/Settings/SchoolCalendar/SchoolCalendarQueryService.php b/app/Services/Settings/SchoolCalendar/SchoolCalendarQueryService.php index 0090ef9f..9688cc42 100644 --- a/app/Services/Settings/SchoolCalendar/SchoolCalendarQueryService.php +++ b/app/Services/Settings/SchoolCalendar/SchoolCalendarQueryService.php @@ -3,6 +3,7 @@ namespace App\Services\Settings\SchoolCalendar; use App\Models\CalendarEvent; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; class SchoolCalendarQueryService @@ -35,7 +36,7 @@ class SchoolCalendarQueryService public function filterEventsForAudience(Collection $events, ?string $audience): Collection { $audience = $audience !== null ? strtolower(trim($audience)) : null; - if (! in_array($audience, ['parent', 'teacher', 'admin'], true)) { + if (!in_array($audience, ['parent', 'teacher', 'admin'], true)) { return $events; } @@ -50,7 +51,7 @@ class SchoolCalendarQueryService return true; } - if (! $hasAny) { + if (!$hasAny) { return true; } diff --git a/app/Services/Settings/SettingsService.php b/app/Services/Settings/SettingsService.php index 6ed06c95..045ae1a4 100644 --- a/app/Services/Settings/SettingsService.php +++ b/app/Services/Settings/SettingsService.php @@ -32,7 +32,7 @@ class SettingsService $updates['timezone'] = $payload['timezone']; } - if (! empty($updates)) { + if (!empty($updates)) { $updates['updated_by'] = $userId; $settings->fill($updates); $settings->save(); diff --git a/app/Services/Staff/StaffCommandService.php b/app/Services/Staff/StaffCommandService.php index edd3fd4d..9aab50c5 100644 --- a/app/Services/Staff/StaffCommandService.php +++ b/app/Services/Staff/StaffCommandService.php @@ -10,7 +10,9 @@ use RuntimeException; class StaffCommandService { - public function __construct(private GlobalConfigService $configService) {} + public function __construct(private GlobalConfigService $configService) + { + } public function create(array $payload): Staff { @@ -19,7 +21,7 @@ class StaffCommandService $roleName = (string) ($payload['role_name'] ?? ''); $activeRole = strtolower($roleName); - if (! empty($payload['status']) && strtolower((string) $payload['status']) === 'inactive') { + if (!empty($payload['status']) && strtolower((string) $payload['status']) === 'inactive') { $activeRole = 'inactive'; } @@ -38,7 +40,7 @@ class StaffCommandService 'updated_at' => now(), ]); - if (! $staff) { + if (!$staff) { throw new RuntimeException('Failed to create staff member.'); } @@ -59,13 +61,13 @@ class StaffCommandService if (array_key_exists('role_name', $updates)) { $updates['active_role'] = strtolower((string) $updates['role_name']); } - if (! empty($payload['status']) && strtolower((string) $payload['status']) === 'inactive') { + if (!empty($payload['status']) && strtolower((string) $payload['status']) === 'inactive') { $updates['active_role'] = 'inactive'; } $updates['updated_at'] = now(); - if (! empty($updates)) { + if (!empty($updates)) { $staff->fill($updates); $staff->save(); } @@ -81,7 +83,7 @@ class StaffCommandService private function resolveUserId(array $payload): int { - if (! empty($payload['user_id'])) { + if (!empty($payload['user_id'])) { return (int) $payload['user_id']; } diff --git a/app/Services/Staff/StaffQueryService.php b/app/Services/Staff/StaffQueryService.php index 29db117b..5e465d95 100644 --- a/app/Services/Staff/StaffQueryService.php +++ b/app/Services/Staff/StaffQueryService.php @@ -6,11 +6,14 @@ use App\Models\Staff; use App\Models\TeacherClass; use App\Models\User; use App\Services\System\GlobalConfigService; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Support\Facades\DB; class StaffQueryService { - public function __construct(private GlobalConfigService $configService) {} + public function __construct(private GlobalConfigService $configService) + { + } public function paginate(array $filters, int $page, int $perPage): array { @@ -19,7 +22,7 @@ class StaffQueryService $query = Staff::query() ->whereNotIn(DB::raw('LOWER(active_role)'), $excluded); - if (! empty($filters['role'])) { + if (!empty($filters['role'])) { $role = strtolower(trim((string) $filters['role'])); $query->whereRaw('LOWER(active_role) = ?', [$role]); } @@ -44,7 +47,7 @@ class StaffQueryService if (in_array($role, ['teacher', 'teacher_assistant'], true)) { $tid = (int) ($staff->user_id ?? 0); $labels = $assignByTeacher[$tid] ?? []; - if (! empty($labels)) { + if (!empty($labels)) { $staff->class_section = implode(', ', array_unique($labels)); $staff->verification_issue = false; } else { @@ -98,10 +101,10 @@ class StaffQueryService continue; } $pos = strtolower((string) ($row->position ?? '')); - if (! in_array($pos, ['main', 'ta'], true)) { + if (!in_array($pos, ['main', 'ta'], true)) { continue; } - $assignByTeacher[$tid][] = $name.' ('.$pos.')'; + $assignByTeacher[$tid][] = $name . ' (' . $pos . ')'; } return $assignByTeacher; diff --git a/app/Services/Staff/StaffTimeOffLinkService.php b/app/Services/Staff/StaffTimeOffLinkService.php index d66f9ea8..c1bd8719 100644 --- a/app/Services/Staff/StaffTimeOffLinkService.php +++ b/app/Services/Staff/StaffTimeOffLinkService.php @@ -5,11 +5,9 @@ namespace App\Services\Staff; class StaffTimeOffLinkService { private const TOKEN_CONTEXT = 'timeoff_notify'; - private const DEFAULT_TTL = 1209600; private string $secret; - private int $ttl; public function __construct(?string $secret = null, ?int $ttlSeconds = null) @@ -32,12 +30,12 @@ class StaffTimeOffLinkService public function parseToken(?string $token): ?array { - if (! is_string($token) || $token === '') { + if (!is_string($token) || $token === '') { return null; } $payload = $this->jwtDecode($token, $this->secret); - if (! is_array($payload)) { + if (!is_array($payload)) { return null; } @@ -79,17 +77,17 @@ class StaffTimeOffLinkService $payload = json_decode($this->base64UrlDecode($payload64), true); $signature = $this->base64UrlDecode($signature64); - if (! is_array($header) || ! is_array($payload)) { + if (!is_array($header) || !is_array($payload)) { return null; } - $signingInput = $header64.'.'.$payload64; + $signingInput = $header64 . '.' . $payload64; if (($header['alg'] ?? '') !== 'HS256') { return null; } $expected = hash_hmac('sha256', $signingInput, $secret, true); - if (! hash_equals($expected, $signature)) { + if (!hash_equals($expected, $signature)) { return null; } @@ -107,7 +105,6 @@ class StaffTimeOffLinkService if ($padding > 0) { $data .= str_repeat('=', 4 - $padding); } - return base64_decode(strtr($data, '-_', '+/')) ?: ''; } } diff --git a/app/Services/Students/StudentAssignmentService.php b/app/Services/Students/StudentAssignmentService.php index a7461e44..c4ff20e2 100644 --- a/app/Services/Students/StudentAssignmentService.php +++ b/app/Services/Students/StudentAssignmentService.php @@ -11,7 +11,9 @@ use Illuminate\Support\Facades\Schema; class StudentAssignmentService { - public function __construct(private StudentConfigService $configService) {} + public function __construct(private StudentConfigService $configService) + { + } public function assignClasses(int $studentId, array $classSectionIds, bool $isEventOnly, ?int $userId = null): array { @@ -25,7 +27,7 @@ class StudentAssignmentService } $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return ['ok' => false, 'message' => 'Student not found.']; } @@ -45,7 +47,7 @@ class StudentAssignmentService } $missing = array_diff($classSectionIds, array_keys($sectionMap)); - if (! empty($missing)) { + if (!empty($missing)) { return ['ok' => false, 'message' => 'One or more selected classes do not exist.']; } @@ -103,7 +105,7 @@ class StudentAssignmentService } } - if (! $isEventOnly) { + if (!$isEventOnly) { $enrollment = Enrollment::query() ->where('student_id', $studentId) ->where('school_year', $schoolYear) @@ -141,12 +143,12 @@ class StudentAssignmentService $displayNames = []; foreach ($classSectionIds as $classSectionId) { $section = $sectionMap[$classSectionId] ?? null; - if (! $section) { + if (!$section) { continue; } $name = (string) ($section['class_section_name'] ?? ''); if ($name === '') { - $name = 'Section #'.$classSectionId; + $name = 'Section #' . $classSectionId; } $displayNames[] = $name; } @@ -178,7 +180,7 @@ class StudentAssignmentService ->where('school_year', $schoolYear) ->first(); - if (! $row) { + if (!$row) { return ['ok' => false, 'message' => 'Assignment not found for this student/class.']; } @@ -210,7 +212,7 @@ class StudentAssignmentService ->first(); if ($enrollment) { - $newClassId = ! empty($remainingIds) ? $remainingIds[0] : null; + $newClassId = !empty($remainingIds) ? $remainingIds[0] : null; if ((int) $enrollment->class_section_id === $classSectionId || $newClassId !== null) { $enrollment->update([ 'class_section_id' => $newClassId, @@ -296,7 +298,7 @@ class StudentAssignmentService $payload['updated_by'] = $modifiedBy; } - $results[$table.'_updated'] = DB::table($table) + $results[$table . '_updated'] = DB::table($table) ->where('student_id', $studentId) ->where('semester', $semester) ->where('school_year', $schoolYear) @@ -310,7 +312,6 @@ class StudentAssignmentService { $values = array_map('intval', $ids); $values = array_values(array_unique(array_filter($values, static fn ($v) => $v > 0))); - return $values; } } diff --git a/app/Services/Students/StudentAutoDistributionService.php b/app/Services/Students/StudentAutoDistributionService.php index 92b4857f..0f857b60 100644 --- a/app/Services/Students/StudentAutoDistributionService.php +++ b/app/Services/Students/StudentAutoDistributionService.php @@ -9,7 +9,9 @@ use Illuminate\Support\Facades\DB; class StudentAutoDistributionService { - public function __construct(private StudentConfigService $configService) {} + public function __construct(private StudentConfigService $configService) + { + } public function promotionTotals(?string $schoolYear = null): array { @@ -28,7 +30,6 @@ class StudentAutoDistributionService $name = strtolower($nameRaw); if ($name === 'kg' || $name === 'youth') { $wanted[] = $row; - continue; } if (ctype_digit($name)) { @@ -166,7 +167,6 @@ class StudentAutoDistributionService $bestIdx = $idx; } } - return $bestIdx; }; diff --git a/app/Services/Students/StudentDirectoryService.php b/app/Services/Students/StudentDirectoryService.php index 27343327..1367ba70 100644 --- a/app/Services/Students/StudentDirectoryService.php +++ b/app/Services/Students/StudentDirectoryService.php @@ -10,7 +10,9 @@ use Illuminate\Support\Facades\DB; class StudentDirectoryService { - public function __construct(private StudentConfigService $configService) {} + public function __construct(private StudentConfigService $configService) + { + } public function assignmentData(?string $schoolYear = null): array { @@ -53,7 +55,7 @@ class StudentDirectoryService $studentId = (int) ($student['id'] ?? 0); $sectionNames = StudentClass::getClassSectionsByStudentIdWithFlags($studentId, $schoolYear, true); $sectionIds = StudentClass::getClassSectionIdsByStudentId($studentId, $schoolYear); - $sectionDisplay = ! empty($sectionNames) ? implode(', ', $sectionNames) : ''; + $sectionDisplay = !empty($sectionNames) ? implode(', ', $sectionNames) : ''; $parentId = (int) ($student['parent_id'] ?? 0); $emergencyInfo = $parentId > 0 @@ -62,7 +64,7 @@ class StudentDirectoryService $studentData[] = [ 'student_id' => $studentId, - 'name' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')), + 'name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')), 'age' => $student['age'] ?? 'N/A', 'email' => $emergencyInfo['email'] ?? '', 'phone' => $emergencyInfo['cellphone'] ?? '', @@ -147,10 +149,9 @@ class StudentDirectoryService $names = $classMap[$studentId] ?? []; $names = array_values(array_unique(array_filter($names))); $student['class_sections'] = $names; - $student['class_section_name'] = ! empty($names) ? implode(', ', $names) : 'No class assigned'; + $student['class_section_name'] = !empty($names) ? implode(', ', $names) : 'No class assigned'; } unset($student); - return $students; }; @@ -187,7 +188,7 @@ class StudentDirectoryService 'school_year', ]) ->when($selectedYear !== '', fn ($q) => $q->where('school_year', $selectedYear)) - ->when(! empty($parentIds), fn ($q) => $q->whereIn('parent_id', $parentIds)) + ->when(!empty($parentIds), fn ($q) => $q->whereIn('parent_id', $parentIds)) ->orderBy('lastname') ->orderBy('firstname') ->get() diff --git a/app/Services/Students/StudentProfileService.php b/app/Services/Students/StudentProfileService.php index c5495f62..975e895a 100644 --- a/app/Services/Students/StudentProfileService.php +++ b/app/Services/Students/StudentProfileService.php @@ -12,7 +12,7 @@ class StudentProfileService public function updateStudent(int $studentId, array $payload): array { $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return ['ok' => false, 'message' => 'Student not found.']; } @@ -43,7 +43,7 @@ class StudentProfileService $shouldSyncAllergies = array_key_exists('allergies', $payload); DB::transaction(function () use ($student, $studentData, $conditions, $allergies): void { - if (! empty($studentData)) { + if (!empty($studentData)) { $student->update($studentData); } @@ -84,7 +84,7 @@ class StudentProfileService private function syncHealthList(int $studentId, string $modelClass, string $field, array $newValues): void { - $model = new $modelClass; + $model = new $modelClass(); $rows = $model->newQuery()->where('student_id', $studentId)->get(['id', $field])->toArray(); $current = []; @@ -111,14 +111,14 @@ class StudentProfileService $toDeleteKeys = array_diff(array_keys($current), array_keys($incoming)); $toInsertKeys = array_diff(array_keys($incoming), array_keys($current)); - if (! empty($toDeleteKeys)) { + if (!empty($toDeleteKeys)) { $ids = array_map(fn ($key) => $byId[$key], $toDeleteKeys); - if (! empty($ids)) { + if (!empty($ids)) { $model->newQuery()->whereIn('id', $ids)->delete(); } } - if (! empty($toInsertKeys)) { + if (!empty($toInsertKeys)) { $batch = []; foreach ($toInsertKeys as $key) { $batch[] = [ @@ -126,7 +126,7 @@ class StudentProfileService $field => $incoming[$key], ]; } - if (! empty($batch)) { + if (!empty($batch)) { $model->newQuery()->insert($batch); } } diff --git a/app/Services/Students/StudentScoreCardService.php b/app/Services/Students/StudentScoreCardService.php index 1400758e..96379ae7 100644 --- a/app/Services/Students/StudentScoreCardService.php +++ b/app/Services/Students/StudentScoreCardService.php @@ -146,7 +146,7 @@ class StudentScoreCardService ->where('id', $studentId) ->first(); - if (! $student) { + if (!$student) { return ['ok' => false, 'message' => 'Student not found.']; } @@ -177,7 +177,6 @@ class StudentScoreCardService if ($ay !== $by) { return strcmp($by, $ay); } - return strcmp((string) ($a['semester'] ?? ''), (string) ($b['semester'] ?? '')); }); @@ -185,7 +184,7 @@ class StudentScoreCardService foreach ($rows as $row) { $year = (string) ($row['school_year'] ?? ''); $score = $row['semester_score'] ?? null; - if ($year === '' || ! is_numeric($score)) { + if ($year === '' || !is_numeric($score)) { continue; } $yearScoreMap[$year][] = (float) $score; @@ -225,14 +224,14 @@ class StudentScoreCardService if ($commentVal === '') { continue; } - $key = $year.'|'.$semester; + $key = $year . '|' . $semester; $commentMap[$key][$type] = $commentVal; } foreach ($rows as &$row) { $year = (string) ($row['school_year'] ?? ''); $semester = strtolower(trim((string) ($row['semester'] ?? ''))); - $row['comments'] = $commentMap[$year.'|'.$semester] ?? []; + $row['comments'] = $commentMap[$year . '|' . $semester] ?? []; $row['year_score'] = $yearAvg[$year] ?? null; } unset($row); diff --git a/app/Services/Students/StudentStatusService.php b/app/Services/Students/StudentStatusService.php index 51faa77e..86b272f6 100644 --- a/app/Services/Students/StudentStatusService.php +++ b/app/Services/Students/StudentStatusService.php @@ -8,7 +8,9 @@ use App\Models\StudentClass; class StudentStatusService { - public function __construct(private StudentConfigService $configService) {} + public function __construct(private StudentConfigService $configService) + { + } public function setActive(int $studentId, bool $isActive, ?int $userId = null): array { @@ -17,7 +19,7 @@ class StudentStatusService $schoolYear = (string) ($context['school_year'] ?? ''); $student = Student::query()->find($studentId); - if (! $student) { + if (!$student) { return ['ok' => false, 'message' => 'Student not found.']; } @@ -34,7 +36,7 @@ class StudentStatusService ->when($schoolYear !== '', fn ($q) => $q->where('school_year', $schoolYear)) ->first(); - if (! $hasCurrentClass) { + if (!$hasCurrentClass) { $lastClass = StudentClass::query() ->where('student_id', $studentId) ->orderByDesc('updated_at') @@ -57,7 +59,7 @@ class StudentStatusService $classLabel = ClassSection::getClassSectionNameBySectionId($restoreClassId); if ($classLabel) { - $message .= ' Class assignment restored to '.$classLabel.'.'; + $message .= ' Class assignment restored to ' . $classLabel . '.'; } } else { $message .= ' No class assignment found for the current term.'; diff --git a/app/Services/Subjects/SubjectCurriculumService.php b/app/Services/Subjects/SubjectCurriculumService.php index 4b4f9f88..232c2748 100644 --- a/app/Services/Subjects/SubjectCurriculumService.php +++ b/app/Services/Subjects/SubjectCurriculumService.php @@ -80,7 +80,7 @@ class SubjectCurriculumService public function update(int $id, array $payload): ?SubjectCurriculum { $entry = SubjectCurriculum::query()->find($id); - if (! $entry) { + if (!$entry) { return null; } @@ -104,7 +104,7 @@ class SubjectCurriculumService public function delete(int $id): bool { $entry = SubjectCurriculum::query()->find($id); - if (! $entry) { + if (!$entry) { return false; } diff --git a/app/Services/Support/ContactMessageService.php b/app/Services/Support/ContactMessageService.php index 6a205c05..4ca3882d 100644 --- a/app/Services/Support/ContactMessageService.php +++ b/app/Services/Support/ContactMessageService.php @@ -7,7 +7,9 @@ use Illuminate\Support\Facades\Log; class ContactMessageService { - public function __construct(private EmailDispatchService $emailService) {} + public function __construct(private EmailDispatchService $emailService) + { + } public function send(array $payload): array { @@ -18,17 +20,17 @@ class ContactMessageService $formatted = "

From: {$name} ({$email})

"; $formatted .= "

Subject: {$subject}

"; - $formatted .= '

'.nl2br($message).'

'; + $formatted .= '

' . nl2br($message) . '

'; $recipient = (string) config('support.contact_email', 'support@alrahmaisgl.org'); $emailSent = false; - if (! app()->runningUnitTests()) { + if (!app()->runningUnitTests()) { $emailSent = $this->emailService->send($recipient, $subject, $formatted, null, $email, $name); } - if (! $emailSent) { - Log::warning('Contact email failed for '.$email); + if (!$emailSent) { + Log::warning('Contact email failed for ' . $email); } return [ diff --git a/app/Services/Support/SupportRequestService.php b/app/Services/Support/SupportRequestService.php index e5bafee0..a70e90cf 100644 --- a/app/Services/Support/SupportRequestService.php +++ b/app/Services/Support/SupportRequestService.php @@ -14,19 +14,20 @@ class SupportRequestService public function __construct( private GlobalConfigService $configService, private EmailDispatchService $emailService - ) {} + ) { + } public function list(int $userId, array $filters, int $page, int $perPage, bool $asAdmin = false): LengthAwarePaginator { $query = SupportRequest::query()->with('user'); - if (! $asAdmin) { + if (!$asAdmin) { $query->where('user_id', $userId); - } elseif (! empty($filters['user_id'])) { + } elseif (!empty($filters['user_id'])) { $query->where('user_id', (int) $filters['user_id']); } - if (! empty($filters['status'])) { + if (!empty($filters['status'])) { $query->where('status', $filters['status']); } @@ -54,7 +55,7 @@ class SupportRequestService $recipient = (string) config('support.contact_email', 'support@alrahmaisgl.org'); $emailSent = false; - if (! app()->runningUnitTests()) { + if (!app()->runningUnitTests()) { $emailSent = $this->emailService->send( $recipient, (string) $payload['subject'], @@ -65,8 +66,8 @@ class SupportRequestService ); } - if (! $emailSent) { - Log::warning('Support email failed for user '.$userId); + if (!$emailSent) { + Log::warning('Support email failed for user ' . $userId); } return [ diff --git a/app/Services/System/CleanupSchedulerService.php b/app/Services/System/CleanupSchedulerService.php index 18d616bd..31e299e7 100644 --- a/app/Services/System/CleanupSchedulerService.php +++ b/app/Services/System/CleanupSchedulerService.php @@ -10,7 +10,7 @@ class CleanupSchedulerService public function shouldRun(string $cacheKey, int $minutes): bool { $lastRun = Cache::get($cacheKey); - if (! $lastRun) { + if (!$lastRun) { return true; } diff --git a/app/Services/System/ConfigUpdateService.php b/app/Services/System/ConfigUpdateService.php index 8aaa3647..163abd26 100644 --- a/app/Services/System/ConfigUpdateService.php +++ b/app/Services/System/ConfigUpdateService.php @@ -24,34 +24,31 @@ class ConfigUpdateService public function runTask(string $task, bool $dry, bool $force, DateTimeZone $tz): array { - if (! isset($this->tasks[$task])) { + if (!isset($this->tasks[$task])) { return ['ok' => false, 'message' => 'Unknown task.']; } - $lockFile = storage_path('app/locks/config_update_'.$task.'.lock'); - if (! is_dir(dirname($lockFile))) { + $lockFile = storage_path('app/locks/config_update_' . $task . '.lock'); + if (!is_dir(dirname($lockFile))) { @mkdir(dirname($lockFile), 0775, true); } $fp = @fopen($lockFile, 'c+'); - if (! $fp) { + if (!$fp) { return ['ok' => false, 'message' => 'Unable to open lock file.']; } - if (! $force && ! flock($fp, LOCK_EX | LOCK_NB)) { + if (!$force && !flock($fp, LOCK_EX | LOCK_NB)) { fclose($fp); - return ['ok' => false, 'message' => 'Task is already running.']; } try { $method = $this->tasks[$task]; $ok = (bool) $this->{$method}($dry, $force, $tz); - return ['ok' => $ok, 'task' => $task]; } catch (\Throwable $e) { - Log::error('ConfigUpdate task failed: '.$e->getMessage()); - + Log::error('ConfigUpdate task failed: ' . $e->getMessage()); return ['ok' => false, 'message' => $e->getMessage()]; } finally { try { @@ -77,12 +74,11 @@ class ConfigUpdateService { $now = new DateTimeImmutable('now', $tz); $isJune1 = $now->format('n-j') === '6-1'; - if (! $isJune1 && ! $force) { + if (!$isJune1 && !$force) { return true; } - $value = $now->format('Y').'-12-31'; - + $value = $now->format('Y') . '-12-31'; return $dry ? true : Configuration::setConfigValueByKey('date_age_reference', $value); } @@ -90,7 +86,7 @@ class ConfigUpdateService { $now = new DateTimeImmutable('now', $tz); $isFeb1 = $now->format('n-j') === '2-1'; - if (! $isFeb1 && ! $force) { + if (!$isFeb1 && !$force) { return true; } @@ -101,7 +97,7 @@ class ConfigUpdateService { $now = new DateTimeImmutable('now', $tz); $isJun1 = $now->format('n-j') === '6-1'; - if (! $isJun1 && ! $force) { + if (!$isJun1 && !$force) { return true; } diff --git a/app/Services/System/HealthCheckService.php b/app/Services/System/HealthCheckService.php index c5e32806..de744997 100644 --- a/app/Services/System/HealthCheckService.php +++ b/app/Services/System/HealthCheckService.php @@ -12,10 +12,10 @@ class HealthCheckService $uploadsBase = storage_path('app/uploads'); $paths = [ 'uploads' => $uploadsBase, - 'uploads/reimbursements' => $uploadsBase.DIRECTORY_SEPARATOR.'reimbursements', - 'uploads/receipts' => $uploadsBase.DIRECTORY_SEPARATOR.'receipts', - 'uploads/checks' => $uploadsBase.DIRECTORY_SEPARATOR.'checks', - 'uploads/early_dismissal_signatures' => $uploadsBase.DIRECTORY_SEPARATOR.'early_dismissal_signatures', + 'uploads/reimbursements' => $uploadsBase . DIRECTORY_SEPARATOR . 'reimbursements', + 'uploads/receipts' => $uploadsBase . DIRECTORY_SEPARATOR . 'receipts', + 'uploads/checks' => $uploadsBase . DIRECTORY_SEPARATOR . 'checks', + 'uploads/early_dismissal_signatures' => $uploadsBase . DIRECTORY_SEPARATOR . 'early_dismissal_signatures', ]; $pathsStatus = []; @@ -48,10 +48,10 @@ class HealthCheckService }, true); $okDb = true; - if ($dbChecks['user_preferences_exists'] && ! $dbChecks['user_preferences_has_timezone']) { + if ($dbChecks['user_preferences_exists'] && !$dbChecks['user_preferences_has_timezone']) { $okDb = false; } - if ($dbChecks['settings_exists'] && ! $dbChecks['settings_has_timezone']) { + if ($dbChecks['settings_exists'] && !$dbChecks['settings_has_timezone']) { $okDb = false; } diff --git a/app/Services/System/TimeService.php b/app/Services/System/TimeService.php index 62eae8f6..2a90a6ed 100644 --- a/app/Services/System/TimeService.php +++ b/app/Services/System/TimeService.php @@ -50,7 +50,7 @@ class TimeService public function toUtc($value, ?string $fromTz = null, string $format = 'Y-m-d H:i:s'): ?string { $dt = $this->parse($value, $fromTz); - if (! $dt) { + if (!$dt) { return null; } @@ -60,7 +60,7 @@ class TimeService public function toLocal($value, ?string $sourceTz = null, ?string $targetTz = null, string $format = 'Y-m-d H:i:s'): ?string { $dt = $this->parse($value, $sourceTz); - if (! $dt) { + if (!$dt) { return null; } @@ -70,7 +70,7 @@ class TimeService public function formatLocal($value, string $format = 'Y-m-d', ?string $sourceTz = null): string { $dt = $this->parse($value, $sourceTz); - if (! $dt) { + if (!$dt) { return ''; } diff --git a/app/Services/Teachers/TeacherAbsenceService.php b/app/Services/Teachers/TeacherAbsenceService.php index cc96011d..43817f7c 100644 --- a/app/Services/Teachers/TeacherAbsenceService.php +++ b/app/Services/Teachers/TeacherAbsenceService.php @@ -2,12 +2,12 @@ namespace App\Services\Teachers; +use App\Services\ApplicationUrlService; +use App\Services\Staff\StaffTimeOffLinkService; use App\Models\StaffAttendance; use App\Models\TeacherClass; use App\Models\User; -use App\Services\ApplicationUrlService; use App\Services\SemesterRangeService; -use App\Services\Staff\StaffTimeOffLinkService; use Carbon\Carbon; use Illuminate\Support\Facades\Mail; @@ -18,7 +18,8 @@ class TeacherAbsenceService private SemesterRangeService $semesterRangeService, private StaffTimeOffLinkService $staffTimeOffLinkService, private ApplicationUrlService $urls, - ) {} + ) { + } public function formData(int $userId): array { @@ -28,7 +29,7 @@ class TeacherAbsenceService $teacher = User::query()->find($userId); $displayName = $teacher - ? trim(($teacher->firstname ?? '').' '.($teacher->lastname ?? '')) + ? trim(($teacher->firstname ?? '') . ' ' . ($teacher->lastname ?? '')) : 'Teacher'; $existing = StaffAttendance::query() @@ -75,7 +76,7 @@ class TeacherAbsenceService } $reasonBase = $reasonType !== '' ? strtolower($reasonType) : ''; - $reason = $reasonBase !== '' ? ($reasonBase.': '.$reasonText) : $reasonText; + $reason = $reasonBase !== '' ? ($reasonBase . ': ' . $reasonText) : $reasonText; $allowedSet = array_fill_keys($this->allowedAbsenceDates($schoolYear), true); $roleName = User::getUserRoleName($userId) ?: null; @@ -96,12 +97,10 @@ class TeacherAbsenceService $parsed = Carbon::createFromFormat('Y-m-d', $date); if ($parsed->format('Y-m-d') !== $date || empty($allowedSet[$date])) { $invalid[] = $date; - continue; } } catch (\Throwable) { $invalid[] = $date; - continue; } @@ -127,10 +126,10 @@ class TeacherAbsenceService } } - if (! empty($invalid)) { + if (!empty($invalid)) { return [ 'ok' => false, - 'message' => 'Invalid dates: '.implode(', ', $invalid), + 'message' => 'Invalid dates: ' . implode(', ', $invalid), 'status' => 422, ]; } @@ -148,7 +147,7 @@ class TeacherAbsenceService return [ 'ok' => true, - 'message' => $saved.' day(s) saved as absent.', + 'message' => $saved . ' day(s) saved as absent.', 'saved' => $saved, 'dates' => $savedDates, 'status' => 200, @@ -212,10 +211,10 @@ class TeacherAbsenceService ): void { try { $user = User::query()->find($userId); - $fullName = trim(($user->firstname ?? '').' '.($user->lastname ?? '')) ?: 'Teacher'; + $fullName = trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? '')) ?: 'Teacher'; $userEmail = $user->email ?? ''; $role = $roleName ?: 'teacher'; - $dateList = ! empty($savedDates) ? implode(', ', $savedDates) : implode(', ', $dates); + $dateList = !empty($savedDates) ? implode(', ', $savedDates) : implode(', ', $dates); $subject = sprintf( 'TimeOff Request: %s (%s) — %s', @@ -228,21 +227,21 @@ class TeacherAbsenceService $assignedText = $this->formatAssignedClasses($userId, $schoolYear, $semester); $body = '
' - .'

New TimeOff Request

' - .'

A staff time-off request was submitted from the teacher portal.

' - .'' - .'' - .'' - .'' - .'' - .'' - .'' - .'' - .'' - .'' - .'' - .'
Name'.e($fullName).'
Email'.e($userEmail).'
Role'.e((string) $role).'
Semester'.e($semester).'
School Year'.e($schoolYear).'
Reason Type'.e($reasonType ?: '-').'
Reason'.e($reasonText).'
Dates'.e($dateList ?: '-').'
Assigned Class(es)'.e($assignedText).'
Submitted At'.e($submittedAt).'
' - .'
'; + . '

New TimeOff Request

' + . '

A staff time-off request was submitted from the teacher portal.

' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '
Name' . e($fullName) . '
Email' . e($userEmail) . '
Role' . e((string) $role) . '
Semester' . e($semester) . '
School Year' . e($schoolYear) . '
Reason Type' . e($reasonType ?: '-') . '
Reason' . e($reasonText) . '
Dates' . e($dateList ?: '-') . '
Assigned Class(es)' . e($assignedText) . '
Submitted At' . e($submittedAt) . '
' + . ''; $token = $this->staffTimeOffLinkService->createToken([ 'uid' => $userId, @@ -257,9 +256,9 @@ class TeacherAbsenceService ]); $notifyUrl = $this->urls->timeoffNotifyUrl($token); - $body .= '

Click Send confirmation email to ' - .e($fullName) - .' so the staff member is notified automatically. This link expires in 14 days.

'; + $body .= '

Click Send confirmation email to ' + . e($fullName) + . ' so the staff member is notified automatically. This link expires in 14 days.

'; $principalEmail = env('PRINCIPAL_EMAIL', 'principal@alrahmaisgl.org'); @@ -284,10 +283,10 @@ class TeacherAbsenceService $name = (string) ($assignment['class_section_name'] ?? ''); $role = (string) ($assignment['teacher_role'] ?? ''); if ($name !== '') { - $parts[] = $role !== '' ? ($name.' ('.$role.')') : $name; + $parts[] = $role !== '' ? ($name . ' (' . $role . ')') : $name; } } - return ! empty($parts) ? implode(', ', $parts) : 'No assigned class'; + return !empty($parts) ? implode(', ', $parts) : 'No assigned class'; } } diff --git a/app/Services/Teachers/TeacherAssignmentService.php b/app/Services/Teachers/TeacherAssignmentService.php index d5890e14..91595428 100644 --- a/app/Services/Teachers/TeacherAssignmentService.php +++ b/app/Services/Teachers/TeacherAssignmentService.php @@ -8,7 +8,9 @@ use App\Models\User; class TeacherAssignmentService { - public function __construct(private TeacherConfigService $configService) {} + public function __construct(private TeacherConfigService $configService) + { + } public function listAssignments(?string $schoolYear = null): array { @@ -51,7 +53,7 @@ class TeacherAssignmentService } $role = strtolower((string) ($assign['position'] ?? '')); - if (! in_array($role, ['main', 'ta'], true)) { + if (!in_array($role, ['main', 'ta'], true)) { continue; } @@ -71,9 +73,9 @@ class TeacherAssignmentService continue; } $assigned = $assignmentMap[$tid] ?? ['main' => [], 'ta' => []]; - $name = trim(($teacher['firstname'] ?? '').' '.($teacher['lastname'] ?? '')); + $name = trim(($teacher['firstname'] ?? '') . ' ' . ($teacher['lastname'] ?? '')); if ($name === '') { - $name = 'User#'.$tid; + $name = 'User#' . $tid; } $teacherData[] = [ @@ -168,7 +170,7 @@ class TeacherAssignmentService $semester = trim((string) ($input['semester'] ?? $context['semester'] ?? '')); $schoolYear = trim((string) ($input['school_year'] ?? $context['school_year'] ?? '')); - if ($teacherId <= 0 || $classSectionId <= 0 || ! in_array($position, ['main', 'ta'], true) || $schoolYear === '' || $semester === '') { + if ($teacherId <= 0 || $classSectionId <= 0 || !in_array($position, ['main', 'ta'], true) || $schoolYear === '' || $semester === '') { return ['ok' => false, 'message' => 'Missing or invalid data for deletion.']; } @@ -180,12 +182,12 @@ class TeacherAssignmentService ->where('position', $position) ->first(); - if (! $assignment) { + if (!$assignment) { return ['ok' => false, 'message' => 'Assignment not found.']; } $assignment->delete(); - return ['ok' => true, 'message' => ucfirst($position).' assignment removed successfully.']; + return ['ok' => true, 'message' => ucfirst($position) . ' assignment removed successfully.']; } } diff --git a/app/Services/Teachers/TeacherDashboardService.php b/app/Services/Teachers/TeacherDashboardService.php index fd677060..ee297c0d 100644 --- a/app/Services/Teachers/TeacherDashboardService.php +++ b/app/Services/Teachers/TeacherDashboardService.php @@ -11,7 +11,9 @@ use Illuminate\Support\Facades\DB; class TeacherDashboardService { - public function __construct(private TeacherConfigService $configService) {} + public function __construct(private TeacherConfigService $configService) + { + } public function classView(int $userId, ?int $requestedClassSectionId = null): array { @@ -27,7 +29,7 @@ class TeacherDashboardService ->map(fn ($r) => strtolower((string) $r)) ->all(); - if (! array_intersect($roles, ['teacher', 'teacher_assistant'])) { + if (!array_intersect($roles, ['teacher', 'teacher_assistant'])) { throw new \RuntimeException('Access denied.'); } @@ -48,24 +50,24 @@ class TeacherDashboardService $activeClassSectionId = null; if ($requestedClassSectionId && in_array($requestedClassSectionId, $classSectionIds, true)) { $activeClassSectionId = $requestedClassSectionId; - } elseif (! empty($classSectionIds)) { + } elseif (!empty($classSectionIds)) { $activeClassSectionId = $classSectionIds[0]; } $studentsBySection = []; - if (! empty($classSectionIds)) { + if (!empty($classSectionIds)) { $students = StudentClass::getStudentsByClassSectionIds($classSectionIds); - if (! empty($students)) { + if (!empty($students)) { $studentIds = array_values(array_unique(array_map( static fn (array $row) => (int) ($row['student_id'] ?? 0), $students ))); $studentIds = array_values(array_filter($studentIds)); - $conditionsByStudent = ! empty($studentIds) + $conditionsByStudent = !empty($studentIds) ? StudentMedicalCondition::getMedicalByStudentIds($studentIds) : []; - $allergiesByStudent = ! empty($studentIds) + $allergiesByStudent = !empty($studentIds) ? StudentAllergy::getAllergiesByStudentIds($studentIds) : []; @@ -87,7 +89,7 @@ class TeacherDashboardService } $assignedNames = []; - if (! empty($classSectionIds)) { + if (!empty($classSectionIds)) { $rows = DB::table('teacher_class as tc') ->select('tc.class_section_id', 'tc.position', 'u.firstname', 'u.lastname') ->join('users as u', 'u.id', '=', 'tc.teacher_id') @@ -101,7 +103,7 @@ class TeacherDashboardService foreach ($rows as $row) { $sid = (int) ($row->class_section_id ?? 0); $pos = strtolower((string) ($row->position ?? '')); - $name = trim(($row->firstname ?? '').' '.($row->lastname ?? '')); + $name = trim(($row->firstname ?? '') . ' ' . ($row->lastname ?? '')); if ($sid === 0 || $name === '') { continue; } diff --git a/app/Services/Ui/UiStyleService.php b/app/Services/Ui/UiStyleService.php index ddbff6fc..76483dcf 100644 --- a/app/Services/Ui/UiStyleService.php +++ b/app/Services/Ui/UiStyleService.php @@ -13,12 +13,10 @@ class UiStyleService $prefs = Preferences::query()->where('user_id', $userId)->first(); if ($prefs) { $prefs->fill($updates)->save(); - return $prefs->fresh(); } $updates['user_id'] = $userId; - return Preferences::query()->create($updates); } @@ -61,7 +59,6 @@ class UiStyleService private function sanitizePaletteKey(?string $value): ?string { $value = trim((string) $value); - return $value === '' ? null : $value; } @@ -71,7 +68,6 @@ class UiStyleService if (in_array($mode, ['light', 'dark', 'auto'], true)) { return $mode; } - return 'auto'; } @@ -82,19 +78,17 @@ class UiStyleService return null; } if ($h[0] !== '#') { - $h = '#'.$h; + $h = '#' . $h; } if (preg_match('/^#([0-9a-fA-F]{3})$/', $h, $m)) { $r = $m[1][0]; $g = $m[1][1]; $b = $m[1][2]; - - return strtoupper('#'.$r.$r.$g.$g.$b.$b); + return strtoupper('#' . $r . $r . $g . $g . $b . $b); } if (preg_match('/^#([0-9a-fA-F]{6})$/', $h)) { return strtoupper($h); } - return null; } } diff --git a/app/Services/Users/DeleteUnverifiedUserService.php b/app/Services/Users/DeleteUnverifiedUserService.php index 08558522..6070640f 100644 --- a/app/Services/Users/DeleteUnverifiedUserService.php +++ b/app/Services/Users/DeleteUnverifiedUserService.php @@ -9,12 +9,14 @@ use Illuminate\Support\Facades\Log; class DeleteUnverifiedUserService { - public function __construct(private AccountEventService $accountEvents) {} + public function __construct(private AccountEventService $accountEvents) + { + } public function deleteAfterTimeout(int $userId, int $timeoutSeconds = 86400): array { $user = User::query()->find($userId); - if (! $user) { + if (!$user) { return ['ok' => false, 'reason' => 'not_found']; } @@ -23,7 +25,7 @@ class DeleteUnverifiedUserService } $lastActivity = $user->updated_at ?? $user->created_at; - if (! $lastActivity) { + if (!$lastActivity) { return ['ok' => false, 'reason' => 'no_timestamp']; } diff --git a/app/Services/Users/InactiveUserCleanupService.php b/app/Services/Users/InactiveUserCleanupService.php index 335b78c6..ccbbac8d 100644 --- a/app/Services/Users/InactiveUserCleanupService.php +++ b/app/Services/Users/InactiveUserCleanupService.php @@ -21,7 +21,6 @@ class InactiveUserCleanupService if (empty($users)) { $orphans = $this->purgeOrphanedUserRoles(); - return [ 'deleted_users' => 0, 'deleted_parents' => 0, diff --git a/app/Services/Users/UserEventService.php b/app/Services/Users/UserEventService.php index 8c8a1cb6..d3c706ef 100644 --- a/app/Services/Users/UserEventService.php +++ b/app/Services/Users/UserEventService.php @@ -7,23 +7,24 @@ use Illuminate\Support\Facades\Log; class UserEventService { - public function __construct(private EmailService $emailService) {} + public function __construct(private EmailService $emailService) + { + } public function handleNewAccountAdded(array $userData): bool { $email = (string) ($userData['email'] ?? ''); if ($email === '') { Log::warning('UserEventService: missing email for welcome message.'); - return false; } - $name = trim((string) (($userData['firstname'] ?? '').' '.($userData['lastname'] ?? ''))); + $name = trim((string) (($userData['firstname'] ?? '') . ' ' . ($userData['lastname'] ?? ''))); $safeName = e($name !== '' ? $name : 'there'); $subject = 'Welcome to Al Rahma Sunday School!'; - $message = '

Hello '.$safeName.',

' - .'

Your account has been created. Welcome to Al Rahma Sunday School.

'; + $message = '

Hello ' . $safeName . ',

' + . '

Your account has been created. Welcome to Al Rahma Sunday School.

'; return $this->emailService->send($email, $subject, $message, 'registration'); } diff --git a/app/Services/Users/UserListService.php b/app/Services/Users/UserListService.php index b3490b88..918773cc 100644 --- a/app/Services/Users/UserListService.php +++ b/app/Services/Users/UserListService.php @@ -40,11 +40,11 @@ class UserListService $parentType = $guardianMap[$userId] ?? ''; $isSecond = false; - if ($userId > 0 && ! empty($secondByUserId[$userId])) { + if ($userId > 0 && !empty($secondByUserId[$userId])) { $isSecond = true; } else { $email = trim(strtolower((string) $user->email)); - if ($email !== '' && ! empty($secondByEmail[$email])) { + if ($email !== '' && !empty($secondByEmail[$email])) { $isSecond = true; } } @@ -91,7 +91,7 @@ class UserListService private function guardianTypeMap(): array { - if (! Schema::hasTable('family_guardians')) { + if (!Schema::hasTable('family_guardians')) { return []; } @@ -119,7 +119,7 @@ class UserListService private function secondParentMaps(): array { - if (! Schema::hasTable('parents')) { + if (!Schema::hasTable('parents')) { return [[], []]; } diff --git a/app/Services/Users/UserManagementService.php b/app/Services/Users/UserManagementService.php index f7cdb33a..2c3911c2 100644 --- a/app/Services/Users/UserManagementService.php +++ b/app/Services/Users/UserManagementService.php @@ -12,7 +12,9 @@ use Illuminate\Support\Facades\Validator; class UserManagementService { - public function __construct(private UserEventService $eventService) {} + public function __construct(private UserEventService $eventService) + { + } public function create(array $payload, ?int $actorId = null): array { @@ -43,7 +45,7 @@ class UserManagementService public function update(int $userId, array $payload): array { $user = User::query()->find($userId); - if (! $user) { + if (!$user) { return ['ok' => false, 'message' => 'User not found.']; } @@ -65,7 +67,7 @@ class UserManagementService public function delete(int $userId): array { $user = User::query()->find($userId); - if (! $user) { + if (!$user) { return ['ok' => false, 'message' => 'User not found.']; } @@ -85,11 +87,11 @@ class UserManagementService { $actorId = $actorId ?? (auth()->id() ?? null); - if (! User::query()->whereKey($userId)->exists()) { + if (!User::query()->whereKey($userId)->exists()) { return false; } - if (! Role::query()->whereKey($roleId)->exists()) { + if (!Role::query()->whereKey($roleId)->exists()) { return false; } @@ -131,10 +133,10 @@ class UserManagementService 'accept_school_policy' => ['required'], ]; - $isParent = ! empty($data['is_parent']); - $noSecondParent = ! empty($data['no_second_parent_info']); + $isParent = !empty($data['is_parent']); + $noSecondParent = !empty($data['no_second_parent_info']); - if ($isParent && ! $noSecondParent) { + if ($isParent && !$noSecondParent) { $rules += [ 'second_firstname' => ['required', 'regex:/^[a-zA-Z\\s\\-]+$/', 'min:2', 'max:30'], 'second_lastname' => ['required', 'regex:/^[a-zA-Z\\s\\-]+$/', 'min:2', 'max:30'], @@ -213,7 +215,7 @@ class UserManagementService ]; foreach ($map as $field) { - if (! array_key_exists($field, $payload)) { + if (!array_key_exists($field, $payload)) { continue; } @@ -263,7 +265,6 @@ class UserManagementService if ($value === 'female') { return 'Female'; } - return null; } @@ -273,7 +274,6 @@ class UserManagementService if ($value === '') { return ''; } - return ucfirst($value); } diff --git a/app/Services/Whatsapp/WhatsappContactService.php b/app/Services/Whatsapp/WhatsappContactService.php index 9ee94188..5075d8ab 100644 --- a/app/Services/Whatsapp/WhatsappContactService.php +++ b/app/Services/Whatsapp/WhatsappContactService.php @@ -8,7 +8,9 @@ use Illuminate\Support\Facades\Log; class WhatsappContactService { - public function __construct(private WhatsappContextService $context) {} + public function __construct(private WhatsappContextService $context) + { + } public function listParentContacts(?string $schoolYear, ?string $semester): array { @@ -16,7 +18,7 @@ class WhatsappContactService $semester = trim((string) $semester); $builder = DB::table('parents as sp'); - $builder->select(' + $builder->select(" sp.id AS parents_row_id, sp.firstparent_id AS firstparent_id, sp.secondparent_firstname AS sp_firstname, @@ -32,7 +34,7 @@ class WhatsappContactService u.cellphone AS u_phone, u.school_year AS u_school_year, u.semester AS u_semester - '); + "); $builder->leftJoin('users as u', 'u.id', '=', 'sp.firstparent_id'); if ($schoolYear !== '') { @@ -47,7 +49,7 @@ class WhatsappContactService $contacts = []; foreach ($rows as $row) { $r = (array) $row; - if (! empty($r['u_id'])) { + if (!empty($r['u_id'])) { $contacts[] = [ 'firstname' => (string) ($r['u_firstname'] ?? ''), 'lastname' => (string) ($r['u_lastname'] ?? ''), @@ -57,7 +59,7 @@ class WhatsappContactService ]; } - $hasSecond = ! empty($r['sp_firstname']) || ! empty($r['sp_lastname']) || ! empty($r['sp_email']) || ! empty($r['sp_phone']); + $hasSecond = !empty($r['sp_firstname']) || !empty($r['sp_lastname']) || !empty($r['sp_email']) || !empty($r['sp_phone']); if ($hasSecond) { $contacts[] = [ 'firstname' => (string) ($r['sp_firstname'] ?? ''), @@ -70,9 +72,8 @@ class WhatsappContactService } $contacts = array_values(array_filter($contacts, function ($c) { - $name = trim(($c['firstname'] ?? '').($c['lastname'] ?? '')); - $contact = trim(($c['phone'] ?? '').($c['email'] ?? '')); - + $name = trim(($c['firstname'] ?? '') . ($c['lastname'] ?? '')); + $contact = trim(($c['phone'] ?? '') . ($c['email'] ?? '')); return $name !== '' || $contact !== ''; })); @@ -89,7 +90,6 @@ class WhatsappContactService } $ta = ($a['type'] ?? '') === 'Primary Parent' ? 0 : 1; $tb = ($b['type'] ?? '') === 'Primary Parent' ? 0 : 1; - return $ta <=> $tb; }); @@ -115,7 +115,7 @@ class WhatsappContactService )))); $namesById = []; - if (! empty($sectionIds)) { + if (!empty($sectionIds)) { $nameRows = DB::table('classSection') ->select('class_section_id', 'class_section_name') ->whereIn('class_section_id', $sectionIds) @@ -130,13 +130,13 @@ class WhatsappContactService $classSections = []; foreach ($sections as $s) { $sid = (int) ($s->class_section_id ?? 0); - if (! $sid) { + if (!$sid) { continue; } $classSections[$sid] = [ 'class_section_id' => $sid, - 'class_section_name' => $namesById[$sid] ?? ('Section '.$sid), + 'class_section_name' => $namesById[$sid] ?? ('Section ' . $sid), 'semester' => $semester, 'school_year' => (string) ($s->school_year ?? ''), 'description' => '', @@ -178,11 +178,11 @@ class WhatsappContactService $r = (array) $row; $sid = (int) ($r['class_section_id'] ?? 0); $pid = (int) ($r['primary_id'] ?? 0); - if (! $sid || ! $pid || ! isset($classSections[$sid])) { + if (!$sid || !$pid || !isset($classSections[$sid])) { continue; } - $key = $sid.':'.$pid; + $key = $sid . ':' . $pid; if (isset($seen[$key])) { continue; } @@ -191,11 +191,11 @@ class WhatsappContactService $classSections[$sid]['parents'][] = [ 'class_section_id' => $sid, 'primary_id' => $pid, - 'primary_name' => trim(($r['primary_lastname'] ?? '').', '.($r['primary_firstname'] ?? '')), + 'primary_name' => trim(($r['primary_lastname'] ?? '') . ', ' . ($r['primary_firstname'] ?? '')), 'primary_phone' => (string) ($r['primary_phone'] ?? ''), 'primary_email' => (string) ($r['primary_email'] ?? ''), 'second_id' => (int) ($r['second_id'] ?? 0), - 'second_name' => trim(($r['second_lastname'] ?? '').', '.($r['second_firstname'] ?? '')), + 'second_name' => trim(($r['second_lastname'] ?? '') . ', ' . ($r['second_firstname'] ?? '')), 'second_phone' => (string) ($r['second_phone'] ?? ''), 'second_email' => (string) ($r['second_email'] ?? ''), 'primary_member' => null, @@ -225,7 +225,7 @@ class WhatsappContactService } unset($section); } catch (\Throwable $e) { - Log::warning('WhatsApp membership lookup failed: '.$e->getMessage()); + Log::warning('WhatsApp membership lookup failed: ' . $e->getMessage()); } try { @@ -239,10 +239,10 @@ class WhatsappContactService foreach ($teachers as $row) { $r = (array) $row; $sid = (int) ($r['class_section_id'] ?? 0); - if (! isset($classSections[$sid])) { + if (!isset($classSections[$sid])) { continue; } - $name = trim(($r['lastname'] ?? '').', '.($r['firstname'] ?? '')); + $name = trim(($r['lastname'] ?? '') . ', ' . ($r['firstname'] ?? '')); $pos = strtolower((string) ($r['position'] ?? 'main')); if ($pos === 'ta' || $pos === 'assistant') { $classSections[$sid]['teacher_assistants'][] = $name; @@ -251,7 +251,7 @@ class WhatsappContactService } } } catch (\Throwable $e) { - Log::warning('WhatsApp teacher list lookup failed: '.$e->getMessage()); + Log::warning('WhatsApp teacher list lookup failed: ' . $e->getMessage()); } foreach ($classSections as &$section) { diff --git a/app/Services/Whatsapp/WhatsappContextService.php b/app/Services/Whatsapp/WhatsappContextService.php index 37a8db4d..de77a5cc 100644 --- a/app/Services/Whatsapp/WhatsappContextService.php +++ b/app/Services/Whatsapp/WhatsappContextService.php @@ -47,11 +47,11 @@ class WhatsappContextService } $end = $start + 1; - $canonical = $start.'-'.$end; + $canonical = $start . '-' . $end; $aliases = [ $canonical, - $start.'/'.$end, + $start . '/' . $end, sprintf('%d-%02d', $start, $end % 100), (string) $start, ]; diff --git a/app/Services/Whatsapp/WhatsappInviteBundleService.php b/app/Services/Whatsapp/WhatsappInviteBundleService.php index e7050066..9e9e8de9 100644 --- a/app/Services/Whatsapp/WhatsappInviteBundleService.php +++ b/app/Services/Whatsapp/WhatsappInviteBundleService.php @@ -13,12 +13,12 @@ class WhatsappInviteBundleService $isPrimary = User::query()->whereKey($pickedId)->exists(); $primaryId = $pickedId; - if (! $isPrimary) { + if (!$isPrimary) { $map = ParentModel::query() ->select('firstparent_id', 'id') ->where('id', $pickedId) ->first(); - if (! $map || ! $map->firstparent_id) { + if (!$map || !$map->firstparent_id) { return null; } $primaryId = (int) $map->firstparent_id; @@ -28,7 +28,7 @@ class WhatsappInviteBundleService ->select('id', 'firstname', 'lastname', 'email') ->whereKey($primaryId) ->first(); - if (! $primary) { + if (!$primary) { return null; } @@ -50,7 +50,7 @@ class WhatsappInviteBundleService $linksSet = []; foreach ($sectionRows as $row) { $cid = (int) ($row->class_section_id ?? 0); - if (! $cid) { + if (!$cid) { continue; } $link = (string) ($linkBySection[$cid]['invite_link'] ?? ''); @@ -60,7 +60,7 @@ class WhatsappInviteBundleService $sections[] = [ 'class_section_id' => $cid, - 'class_section_name' => (string) ($linkBySection[$cid]['class_section_name'] ?? ('Section '.$cid)), + 'class_section_name' => (string) ($linkBySection[$cid]['class_section_name'] ?? ('Section ' . $cid)), 'invite_link' => $link, ]; $linksSet[$link] = true; @@ -71,10 +71,10 @@ class WhatsappInviteBundleService } $emails = []; - if (! empty($primary->email)) { + if (!empty($primary->email)) { $emails[$primary->email] = true; } - if (! empty($secondary?->secondparent_email)) { + if (!empty($secondary?->secondparent_email)) { $emails[$secondary->secondparent_email] = true; } if (empty($emails)) { @@ -89,7 +89,7 @@ class WhatsappInviteBundleService 'email' => (string) ($primary->email ?? ''), 'source' => 'users', ], - 'secondary_parents' => $secondary && ! empty($secondary->id) ? [[ + 'secondary_parents' => $secondary && !empty($secondary->id) ? [[ 'id' => (int) $secondary->id, 'firstname' => (string) ($secondary->secondparent_firstname ?? ''), 'lastname' => (string) ($secondary->secondparent_lastname ?? ''), @@ -186,15 +186,15 @@ class WhatsappInviteBundleService $bundles = []; foreach ($parentIds as $pid) { $profile = $profiles[$pid] ?? null; - if (! $profile) { + if (!$profile) { continue; } $emails = []; - if (! empty($profile['email'])) { + if (!empty($profile['email'])) { $emails[$profile['email']] = true; } - if (! empty($secondaryByPrimary[$pid]['email'])) { + if (!empty($secondaryByPrimary[$pid]['email'])) { $emails[$secondaryByPrimary[$pid]['email']] = true; } if (empty($emails)) { @@ -203,10 +203,10 @@ class WhatsappInviteBundleService $bundles[] = [ 'parent' => $profile, - 'secondary_parents' => ! empty($secondaryByPrimary[$pid]['id']) ? [$secondaryByPrimary[$pid]] : [], + 'secondary_parents' => !empty($secondaryByPrimary[$pid]['id']) ? [$secondaryByPrimary[$pid]] : [], 'sections' => [[ 'class_section_id' => $classSectionId, - 'class_section_name' => (string) ($linkBySection[$classSectionId]['class_section_name'] ?? ('Section '.$classSectionId)), + 'class_section_name' => (string) ($linkBySection[$classSectionId]['class_section_name'] ?? ('Section ' . $classSectionId)), 'invite_link' => $link, ]], 'links' => [$link], @@ -232,7 +232,7 @@ class WhatsappInviteBundleService $bundles = []; foreach ($sectionRows as $row) { $cid = (int) ($row->class_section_id ?? 0); - if (! $cid) { + if (!$cid) { continue; } @@ -255,7 +255,6 @@ class WhatsappInviteBundleService $out[$e] = true; } } - return array_keys($out); }; @@ -265,7 +264,6 @@ class WhatsappInviteBundleService $k = is_array($v) ? md5(json_encode($v)) : (string) $v; $map[$k] = $v; } - return array_values($map); }; @@ -275,10 +273,10 @@ class WhatsappInviteBundleService if (is_array($row)) { $id = $row['class_section_id'] ?? null; $name = $row['class_section_name'] ?? null; - $key = $id !== null ? ('id:'.(int) $id) : ('name:'.(string) $name); + $key = $id !== null ? ('id:' . (int) $id) : ('name:' . (string) $name); $byKey[$key] = $row; } else { - $byKey['name:'.(string) $row] = $row; + $byKey['name:' . (string) $row] = $row; } }; @@ -297,11 +295,11 @@ class WhatsappInviteBundleService $add = static function (&$index, $item) { if (is_array($item)) { $key = isset($item['class_section_id']) - ? 'id:'.(int) $item['class_section_id'] - : ('url:'.(string) ($item['invite_link'] ?? json_encode($item))); + ? 'id:' . (int) $item['class_section_id'] + : ('url:' . (string) ($item['invite_link'] ?? json_encode($item))); $index[$key] = $item; } else { - $index['url:'.(string) $item] = $item; + $index['url:' . (string) $item] = $item; } }; @@ -320,9 +318,9 @@ class WhatsappInviteBundleService $parent = $bundle['parent'] ?? []; $pid = (int) ($parent['id'] ?? 0); $primaryEmails = $normalizeEmails((array) ($bundle['emails'] ?? [])); - $groupKey = $pid > 0 ? ('pid:'.$pid) : ('mail:'.implode(',', $primaryEmails)); + $groupKey = $pid > 0 ? ('pid:' . $pid) : ('mail:' . implode(',', $primaryEmails)); - if (! isset($grouped[$groupKey])) { + if (!isset($grouped[$groupKey])) { $grouped[$groupKey] = [ 'parent' => $parent, 'emails' => $primaryEmails, @@ -332,11 +330,10 @@ class WhatsappInviteBundleService 'items' => (array) ($bundle['items'] ?? []), 'secondary_parents' => (array) ($bundle['secondary_parents'] ?? []), ]; - continue; } - $grouped[$groupKey]['parent'] = ! empty($parent) ? $parent : $grouped[$groupKey]['parent']; + $grouped[$groupKey]['parent'] = !empty($parent) ? $parent : $grouped[$groupKey]['parent']; $grouped[$groupKey]['emails'] = $normalizeEmails(array_merge($grouped[$groupKey]['emails'], $primaryEmails)); $grouped[$groupKey]['sections'] = $mergeSections($grouped[$groupKey]['sections'], (array) ($bundle['sections'] ?? [])); $grouped[$groupKey]['links'] = $mergeLinks($grouped[$groupKey]['links'], (array) ($bundle['links'] ?? [])); diff --git a/app/Services/Whatsapp/WhatsappInviteEmailService.php b/app/Services/Whatsapp/WhatsappInviteEmailService.php index 18911451..b70f42d8 100644 --- a/app/Services/Whatsapp/WhatsappInviteEmailService.php +++ b/app/Services/Whatsapp/WhatsappInviteEmailService.php @@ -8,7 +8,9 @@ use Illuminate\Support\Facades\Log; class WhatsappInviteEmailService { - public function __construct(private EmailService $emailService) {} + public function __construct(private EmailService $emailService) + { + } public function send(array $payload): array { @@ -16,13 +18,12 @@ class WhatsappInviteEmailService $cc = array_values(array_unique(array_filter((array) ($payload['cc_emails'] ?? [])))); $cc = array_values(array_diff($cc, $to)); - if (empty($to) && ! empty($cc)) { + if (empty($to) && !empty($cc)) { $to = $cc; $cc = []; } if (empty($to)) { Log::warning('WhatsappInvite: no recipients after normalization.'); - return ['ok' => false, 'message' => 'No recipients provided.']; } @@ -33,7 +34,6 @@ class WhatsappInviteEmailService $items = $this->buildItems($sections, $links); if (empty($items)) { Log::warning('WhatsappInvite: no invite items built.'); - return ['ok' => false, 'message' => 'No invite links found.']; } @@ -77,12 +77,12 @@ class WhatsappInviteEmailService foreach ($sections as $section) { $sid = isset($section['class_section_id']) ? (int) $section['class_section_id'] : 0; - $name = trim((string) ($section['class_section_name'] ?? ($sid ? ('Section '.$sid) : 'Class'))); + $name = trim((string) ($section['class_section_name'] ?? ($sid ? ('Section ' . $sid) : 'Class'))); $url = trim((string) ($section['invite_link'] ?? '')); if ($url === '') { continue; } - $key = $sid.'|'.$url; + $key = $sid . '|' . $url; if (isset($seen[$key])) { continue; } @@ -96,20 +96,20 @@ class WhatsappInviteEmailService ]; } - if (empty($items) && ! empty($links)) { + if (empty($items) && !empty($links)) { foreach ($links as $i => $url) { $url = trim((string) $url); if ($url === '') { continue; } - $key = '0|'.$url; + $key = '0|' . $url; if (isset($seen[$key])) { continue; } $seen[$key] = true; $items[] = [ 'class_section_id' => 0, - 'class_section_name' => 'Class Link '.($i + 1), + 'class_section_name' => 'Class Link ' . ($i + 1), 'invite_link' => $url, 'qr_src' => $this->generateQrImage($url), ]; @@ -126,23 +126,21 @@ class WhatsappInviteEmailService } $dir = storage_path('app/qrcodes'); - if (! is_dir($dir)) { - if (! @mkdir($dir, 0775, true) && ! is_dir($dir)) { + if (!is_dir($dir)) { + if (!@mkdir($dir, 0775, true) && !is_dir($dir)) { Log::error('QR: cannot create dir', ['dir' => $dir]); - return $this->qrFallback($inviteLink); } } - if (! is_writable($dir)) { + if (!is_writable($dir)) { Log::error('QR: dir not writable', ['dir' => $dir]); - return $this->qrFallback($inviteLink); } - $filename = 'wa_'.md5($inviteLink).'.png'; - $path = $dir.DIRECTORY_SEPARATOR.$filename; + $filename = 'wa_' . md5($inviteLink) . '.png'; + $path = $dir . DIRECTORY_SEPARATOR . $filename; - if (! is_file($path)) { + if (!is_file($path)) { $v5BuilderClass = '\\Endroid\\QrCode\\Builder\\Builder'; $v5WriterClass = '\\Endroid\\QrCode\\Writer\\PngWriter'; $v5Encoding = '\\Endroid\\QrCode\\Encoding\\Encoding'; @@ -159,7 +157,7 @@ class WhatsappInviteEmailService if (class_exists($v5BuilderClass) && class_exists($v5WriterClass)) { try { $builder = $v5BuilderClass::create() - ->writer(new $v5WriterClass) + ->writer(new $v5WriterClass()) ->data($inviteLink); if (class_exists($v5Encoding)) { $builder->encoding(new $v5Encoding('UTF-8')); @@ -167,11 +165,11 @@ class WhatsappInviteEmailService $result = $builder->size(500)->margin(2)->build(); $result->saveToFile($path); } catch (\Throwable $e) { - $lastErr = 'Endroid v5: '.$e->getMessage(); + $lastErr = 'Endroid v5: ' . $e->getMessage(); } } - if (! is_file($path) && class_exists($writerClass)) { + if (!is_file($path) && class_exists($writerClass)) { try { if (class_exists($qrClass) && method_exists($qrClass, 'create')) { $qr = $qrClass::create($inviteLink); @@ -185,7 +183,7 @@ class WhatsappInviteEmailService if (method_exists($qr, 'setMargin')) { $qr->setMargin(2); } - $writer = new $writerClass; + $writer = new $writerClass(); $result = $writer->write($qr); if (method_exists($result, 'saveToFile')) { $result->saveToFile($path); @@ -195,21 +193,21 @@ class WhatsappInviteEmailService } } } catch (\Throwable $e) { - $lastErr = 'Endroid v3/v4: '.$e->getMessage(); + $lastErr = 'Endroid v3/v4: ' . $e->getMessage(); } } - if (! is_file($path) && class_exists($chlQRCode) && class_exists($chlQROptions)) { + if (!is_file($path) && class_exists($chlQRCode) && class_exists($chlQROptions)) { try { $optsArr = [ 'version' => 5, - 'outputType' => constant($chlQRCode.'::OUTPUT_IMAGE_PNG'), + 'outputType' => constant($chlQRCode . '::OUTPUT_IMAGE_PNG'), 'scale' => 6, 'imageBase64' => false, 'quietzoneSize' => 2, ]; - if (class_exists($chlQRMatrix) && defined($chlQRMatrix.'::ECC_H')) { - $optsArr['eccLevel'] = constant($chlQRMatrix.'::ECC_H'); + if (class_exists($chlQRMatrix) && defined($chlQRMatrix . '::ECC_H')) { + $optsArr['eccLevel'] = constant($chlQRMatrix . '::ECC_H'); } $opts = new $chlQROptions($optsArr); @@ -217,11 +215,11 @@ class WhatsappInviteEmailService $png = $qrcode->render($inviteLink); file_put_contents($path, $png); } catch (\Throwable $e) { - $lastErr = 'chillerlan: '.$e->getMessage(); + $lastErr = 'chillerlan: ' . $e->getMessage(); } } - if (! is_file($path) && $lastErr) { + if (!is_file($path) && $lastErr) { Log::error('QR generation failed', ['error' => $lastErr]); } } @@ -229,7 +227,7 @@ class WhatsappInviteEmailService if (is_file($path)) { $data = @file_get_contents($path); if ($data !== false) { - return 'data:image/png;base64,'.base64_encode($data); + return 'data:image/png;base64,' . base64_encode($data); } } @@ -239,7 +237,6 @@ class WhatsappInviteEmailService private function qrFallback(string $inviteLink): string { $link = rawurlencode($inviteLink); - - return 'https://api.qrserver.com/v1/create-qr-code/?size=260x260&qzone=2&data='.$link; + return 'https://api.qrserver.com/v1/create-qr-code/?size=260x260&qzone=2&data=' . $link; } } diff --git a/app/Services/Whatsapp/WhatsappInviteNotificationService.php b/app/Services/Whatsapp/WhatsappInviteNotificationService.php index 91183220..6396bdc2 100644 --- a/app/Services/Whatsapp/WhatsappInviteNotificationService.php +++ b/app/Services/Whatsapp/WhatsappInviteNotificationService.php @@ -14,7 +14,6 @@ class WhatsappInviteNotificationService $listenerCount = Event::hasListeners(WhatsappInvitesSend::class) ? 1 : 0; if ($listenerCount === 0) { Log::warning('WhatsappInvitesSend has no listeners registered.'); - return [ 'ok' => false, 'message' => 'No event listener registered for WhatsappInvitesSend.', @@ -30,7 +29,6 @@ class WhatsappInviteNotificationService $out[$e] = true; } } - return array_keys($out); }; @@ -49,9 +47,9 @@ class WhatsappInviteNotificationService $to = $primaryEmails; $cc = []; - if (! empty($primaryEmails) && ! empty($secondaryEmails)) { + if (!empty($primaryEmails) && !empty($secondaryEmails)) { $cc = array_values(array_diff($secondaryEmails, $primaryEmails)); - } elseif (empty($primaryEmails) && ! empty($secondaryEmails)) { + } elseif (empty($primaryEmails) && !empty($secondaryEmails)) { $to = $secondaryEmails; } @@ -59,7 +57,6 @@ class WhatsappInviteNotificationService Log::warning('Skipping WhatsApp invite: no recipient email(s).', [ 'parent_id' => $bundle['parent']['id'] ?? null, ]); - continue; } @@ -76,7 +73,7 @@ class WhatsappInviteNotificationService $triggered++; } catch (\Throwable $e) { - Log::error('WhatsappInvitesSend dispatch failed: '.$e->getMessage()); + Log::error('WhatsappInvitesSend dispatch failed: ' . $e->getMessage()); } } @@ -90,12 +87,12 @@ class WhatsappInviteNotificationService { $collected = []; - if (! empty($bundle['emails_secondary'])) { + if (!empty($bundle['emails_secondary'])) { $collected = array_merge($collected, (array) $bundle['emails_secondary']); } - if (! empty($bundle['secondary_parents'])) { + if (!empty($bundle['secondary_parents'])) { foreach ((array) $bundle['secondary_parents'] as $sp) { - if (! empty($sp['email'])) { + if (!empty($sp['email'])) { $collected[] = $sp['email']; } } @@ -103,11 +100,11 @@ class WhatsappInviteNotificationService $parent = $bundle['parent'] ?? []; foreach (['secondary_email', 'secondparent_email', 'sec_email', 'email_secondary'] as $key) { - if (! empty($parent[$key])) { + if (!empty($parent[$key])) { $collected[] = $parent[$key]; } } - if (! empty($parent['secondparent']['email'])) { + if (!empty($parent['secondparent']['email'])) { $collected[] = $parent['secondparent']['email']; } @@ -119,12 +116,12 @@ class WhatsappInviteNotificationService ->where('firstparent_id', $primaryId) ->orderByDesc('updated_at') ->first(); - if (! empty($row?->secondparent_email)) { + if (!empty($row?->secondparent_email)) { $collected[] = $row->secondparent_email; } } } catch (\Throwable $e) { - Log::warning('Secondary email DB lookup failed: '.$e->getMessage()); + Log::warning('Secondary email DB lookup failed: ' . $e->getMessage()); } return $normalize($collected); diff --git a/app/Services/Whatsapp/WhatsappInviteService.php b/app/Services/Whatsapp/WhatsappInviteService.php index d9324092..16357587 100644 --- a/app/Services/Whatsapp/WhatsappInviteService.php +++ b/app/Services/Whatsapp/WhatsappInviteService.php @@ -10,7 +10,8 @@ class WhatsappInviteService private WhatsappContextService $context, private WhatsappInviteBundleService $bundleService, private WhatsappInviteNotificationService $notificationService - ) {} + ) { + } public function send(array $payload): array { @@ -24,7 +25,7 @@ class WhatsappInviteService $linkBySection = []; foreach ($links as $link) { $cid = (int) ($link->class_section_id ?? 0); - if ($cid && ! isset($linkBySection[$cid])) { + if ($cid && !isset($linkBySection[$cid])) { $linkBySection[$cid] = $link->toArray(); } } @@ -37,7 +38,7 @@ class WhatsappInviteService continue; } $bundle = $this->bundleService->bundleForParent($pickedId, $linkBySection, $schoolYear, $semester); - if ($bundle && ! empty($bundle['emails']) && ! empty($bundle['links'])) { + if ($bundle && !empty($bundle['emails']) && !empty($bundle['links'])) { $bundles[] = $bundle; } } @@ -45,14 +46,14 @@ class WhatsappInviteService $classSectionId = (int) ($payload['class_section_id'] ?? 0); $classBundles = $this->bundleService->bundlesForClass($classSectionId, $linkBySection, $schoolYear, $semester); foreach ($classBundles as $bundle) { - if (! empty($bundle['emails']) && ! empty($bundle['links'])) { + if (!empty($bundle['emails']) && !empty($bundle['links'])) { $bundles[] = $bundle; } } } elseif ($mode === 'all') { $allBundles = $this->bundleService->bundlesForAll($linkBySection, $schoolYear, $semester); foreach ($allBundles as $bundle) { - if (! empty($bundle['emails']) && ! empty($bundle['links'])) { + if (!empty($bundle['emails']) && !empty($bundle['links'])) { $bundles[] = $bundle; } } @@ -69,7 +70,7 @@ class WhatsappInviteService $consolidated = $this->bundleService->consolidateBundles($bundles); $result = $this->notificationService->dispatch($consolidated, $schoolYear, $semester); - if (! ($result['ok'] ?? false)) { + if (!($result['ok'] ?? false)) { return $result + ['ok' => false]; } diff --git a/app/Services/Whatsapp/WhatsappLinkService.php b/app/Services/Whatsapp/WhatsappLinkService.php index e9983575..03e5f727 100644 --- a/app/Services/Whatsapp/WhatsappLinkService.php +++ b/app/Services/Whatsapp/WhatsappLinkService.php @@ -9,7 +9,9 @@ use Illuminate\Database\Eloquent\ModelNotFoundException; class WhatsappLinkService { - public function __construct(private WhatsappContextService $context) {} + public function __construct(private WhatsappContextService $context) + { + } public function paginate(array $filters): LengthAwarePaginator { @@ -27,7 +29,7 @@ class WhatsappLinkService } } - if (! empty($filters['class_section_id'])) { + if (!empty($filters['class_section_id'])) { $query->forSection((int) $filters['class_section_id']); } @@ -35,11 +37,11 @@ class WhatsappLinkService $query->where('active', (int) (bool) $filters['active']); } - if (! empty($filters['search'])) { + if (!empty($filters['search'])) { $search = trim((string) $filters['search']); $query->where(function ($q) use ($search) { - $q->where('class_section_name', 'like', '%'.$search.'%') - ->orWhere('invite_link', 'like', '%'.$search.'%') + $q->where('class_section_name', 'like', '%' . $search . '%') + ->orWhere('invite_link', 'like', '%' . $search . '%') ->orWhere('class_section_id', $search); }); } @@ -48,7 +50,7 @@ class WhatsappLinkService $sortDir = strtolower((string) ($filters['sort_dir'] ?? 'desc')) === 'asc' ? 'asc' : 'desc'; $allowedSorts = ['class_section_id', 'class_section_name', 'school_year', 'semester', 'active', 'updated_at']; - if (! in_array($sortBy, $allowedSorts, true)) { + if (!in_array($sortBy, $allowedSorts, true)) { $sortBy = 'updated_at'; } @@ -61,7 +63,7 @@ class WhatsappLinkService public function findOrFail(int $id): WhatsappGroupLink { $link = WhatsappGroupLink::query()->find($id); - if (! $link) { + if (!$link) { throw new ModelNotFoundException('WhatsApp group link not found.'); } @@ -81,7 +83,7 @@ class WhatsappLinkService $link = WhatsappGroupLink::upsertLinkForSection( $sectionId, - $sectionName !== '' ? $sectionName : ('Section '.$sectionId), + $sectionName !== '' ? $sectionName : ('Section ' . $sectionId), $schoolYear, $semester, (string) ($payload['invite_link'] ?? ''), @@ -97,7 +99,7 @@ class WhatsappLinkService if (array_key_exists('class_section_name', $payload)) { $name = trim((string) ($payload['class_section_name'] ?? '')); - if ($name === '' && ! empty($payload['class_section_id'])) { + if ($name === '' && !empty($payload['class_section_id'])) { $name = $this->resolveSectionName((int) $payload['class_section_id']); } $payload['class_section_name'] = $name; @@ -118,7 +120,6 @@ class WhatsappLinkService private function resolveSectionName(int $sectionId): string { $name = ClassSection::getClassSectionNameBySectionId($sectionId); - - return $name !== null && $name !== '' ? $name : ('Section '.$sectionId); + return $name !== null && $name !== '' ? $name : ('Section ' . $sectionId); } } diff --git a/app/Services/Whatsapp/WhatsappMembershipService.php b/app/Services/Whatsapp/WhatsappMembershipService.php index 301e2770..cf6189e4 100644 --- a/app/Services/Whatsapp/WhatsappMembershipService.php +++ b/app/Services/Whatsapp/WhatsappMembershipService.php @@ -11,9 +11,8 @@ class WhatsappMembershipService { public function updateMembership(array $payload, ?int $verifiedBy = null): array { - if (! Schema::hasTable('whatsapp_group_memberships')) { + if (!Schema::hasTable('whatsapp_group_memberships')) { Log::error('WhatsApp membership table missing.'); - return [ 'ok' => false, 'message' => 'Membership table missing. Please run migrations.', @@ -57,7 +56,7 @@ class WhatsappMembershipService (bool) $primaryMember, $verifiedBy ); - $saved[] = 'primary='.$primaryId.':'.($primaryMember ? '1' : '0'); + $saved[] = 'primary=' . $primaryId . ':' . ($primaryMember ? '1' : '0'); if ($id <= 0) { Log::warning('Failed to upsert primary membership.', [ 'class_section_id' => $classSectionId, @@ -76,7 +75,7 @@ class WhatsappMembershipService (bool) $secondMember, $verifiedBy ); - $saved[] = 'second='.$secondId.':'.($secondMember ? '1' : '0'); + $saved[] = 'second=' . $secondId . ':' . ($secondMember ? '1' : '0'); if ($id <= 0) { Log::warning('Failed to upsert second membership.', [ 'class_section_id' => $classSectionId, diff --git a/app/Support/MailHtml.php b/app/Support/MailHtml.php index ee7ea41d..df06e07f 100644 --- a/app/Support/MailHtml.php +++ b/app/Support/MailHtml.php @@ -12,12 +12,12 @@ final class MailHtml $t = htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); return '' - .'' - .''.$t.'' - .'' - .'
' + . '' + . ''.$t.'' + . '' + . '
' .$bodyInnerHtml - .'
'; + . '
'; } /** Late slip PDF body (Dompdf). */ diff --git a/app/Support/SessionTimeoutConfig.php b/app/Support/SessionTimeoutConfig.php index b7b6ff16..f8cce002 100644 --- a/app/Support/SessionTimeoutConfig.php +++ b/app/Support/SessionTimeoutConfig.php @@ -5,8 +5,6 @@ namespace App\Support; class SessionTimeoutConfig { public const TIMEOUT_DURATION = 1200; - public const WARNING_THRESHOLD = 900; - public const CHECK_INTERVAL = 60; } diff --git a/app/ThirdParty/fpdf/font/courier.php b/app/ThirdParty/fpdf/font/courier.php index 09219989..bc8478eb 100644 --- a/app/ThirdParty/fpdf/font/courier.php +++ b/app/ThirdParty/fpdf/font/courier.php @@ -1,11 +1,10 @@ [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/courierb.php b/app/ThirdParty/fpdf/font/courierb.php index 33bbd222..97ecd701 100644 --- a/app/ThirdParty/fpdf/font/courierb.php +++ b/app/ThirdParty/fpdf/font/courierb.php @@ -1,11 +1,10 @@ [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/courierbi.php b/app/ThirdParty/fpdf/font/courierbi.php index c9763421..c4bfff88 100644 --- a/app/ThirdParty/fpdf/font/courierbi.php +++ b/app/ThirdParty/fpdf/font/courierbi.php @@ -1,11 +1,10 @@ [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/courieri.php b/app/ThirdParty/fpdf/font/courieri.php index ba94e54b..015a15ad 100644 --- a/app/ThirdParty/fpdf/font/courieri.php +++ b/app/ThirdParty/fpdf/font/courieri.php @@ -1,11 +1,10 @@ [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/helvetica.php b/app/ThirdParty/fpdf/font/helvetica.php index 3dcf5e5d..927759b9 100644 --- a/app/ThirdParty/fpdf/font/helvetica.php +++ b/app/ThirdParty/fpdf/font/helvetica.php @@ -1,21 +1,21 @@ 278, chr(1) => 278, chr(2) => 278, chr(3) => 278, chr(4) => 278, chr(5) => 278, chr(6) => 278, chr(7) => 278, chr(8) => 278, chr(9) => 278, chr(10) => 278, chr(11) => 278, chr(12) => 278, chr(13) => 278, chr(14) => 278, chr(15) => 278, chr(16) => 278, chr(17) => 278, chr(18) => 278, chr(19) => 278, chr(20) => 278, chr(21) => 278, - chr(22) => 278, chr(23) => 278, chr(24) => 278, chr(25) => 278, chr(26) => 278, chr(27) => 278, chr(28) => 278, chr(29) => 278, chr(30) => 278, chr(31) => 278, ' ' => 278, '!' => 278, '"' => 355, '#' => 556, '$' => 556, '%' => 889, '&' => 667, '\'' => 191, '(' => 333, ')' => 333, '*' => 389, '+' => 584, - ',' => 278, '-' => 333, '.' => 278, '/' => 278, '0' => 556, '1' => 556, '2' => 556, '3' => 556, '4' => 556, '5' => 556, '6' => 556, '7' => 556, '8' => 556, '9' => 556, ':' => 278, ';' => 278, '<' => 584, '=' => 584, '>' => 584, '?' => 556, '@' => 1015, 'A' => 667, - 'B' => 667, 'C' => 722, 'D' => 722, 'E' => 667, 'F' => 611, 'G' => 778, 'H' => 722, 'I' => 278, 'J' => 500, 'K' => 667, 'L' => 556, 'M' => 833, 'N' => 722, 'O' => 778, 'P' => 667, 'Q' => 778, 'R' => 722, 'S' => 667, 'T' => 611, 'U' => 722, 'V' => 667, 'W' => 944, - 'X' => 667, 'Y' => 667, 'Z' => 611, '[' => 278, '\\' => 278, ']' => 278, '^' => 469, '_' => 556, '`' => 333, 'a' => 556, 'b' => 556, 'c' => 500, 'd' => 556, 'e' => 556, 'f' => 278, 'g' => 556, 'h' => 556, 'i' => 222, 'j' => 222, 'k' => 500, 'l' => 222, 'm' => 833, - 'n' => 556, 'o' => 556, 'p' => 556, 'q' => 556, 'r' => 333, 's' => 500, 't' => 278, 'u' => 556, 'v' => 500, 'w' => 722, 'x' => 500, 'y' => 500, 'z' => 500, '{' => 334, '|' => 260, '}' => 334, '~' => 584, chr(127) => 350, chr(128) => 556, chr(129) => 350, chr(130) => 222, chr(131) => 556, - chr(132) => 333, chr(133) => 1000, chr(134) => 556, chr(135) => 556, chr(136) => 333, chr(137) => 1000, chr(138) => 667, chr(139) => 333, chr(140) => 1000, chr(141) => 350, chr(142) => 611, chr(143) => 350, chr(144) => 350, chr(145) => 222, chr(146) => 222, chr(147) => 333, chr(148) => 333, chr(149) => 350, chr(150) => 556, chr(151) => 1000, chr(152) => 333, chr(153) => 1000, - chr(154) => 500, chr(155) => 333, chr(156) => 944, chr(157) => 350, chr(158) => 500, chr(159) => 667, chr(160) => 278, chr(161) => 333, chr(162) => 556, chr(163) => 556, chr(164) => 556, chr(165) => 556, chr(166) => 260, chr(167) => 556, chr(168) => 333, chr(169) => 737, chr(170) => 370, chr(171) => 556, chr(172) => 584, chr(173) => 333, chr(174) => 737, chr(175) => 333, - chr(176) => 400, chr(177) => 584, chr(178) => 333, chr(179) => 333, chr(180) => 333, chr(181) => 556, chr(182) => 537, chr(183) => 278, chr(184) => 333, chr(185) => 333, chr(186) => 365, chr(187) => 556, chr(188) => 834, chr(189) => 834, chr(190) => 834, chr(191) => 611, chr(192) => 667, chr(193) => 667, chr(194) => 667, chr(195) => 667, chr(196) => 667, chr(197) => 667, - chr(198) => 1000, chr(199) => 722, chr(200) => 667, chr(201) => 667, chr(202) => 667, chr(203) => 667, chr(204) => 278, chr(205) => 278, chr(206) => 278, chr(207) => 278, chr(208) => 722, chr(209) => 722, chr(210) => 778, chr(211) => 778, chr(212) => 778, chr(213) => 778, chr(214) => 778, chr(215) => 584, chr(216) => 778, chr(217) => 722, chr(218) => 722, chr(219) => 722, - chr(220) => 722, chr(221) => 667, chr(222) => 667, chr(223) => 611, chr(224) => 556, chr(225) => 556, chr(226) => 556, chr(227) => 556, chr(228) => 556, chr(229) => 556, chr(230) => 889, chr(231) => 500, chr(232) => 556, chr(233) => 556, chr(234) => 556, chr(235) => 556, chr(236) => 278, chr(237) => 278, chr(238) => 278, chr(239) => 278, chr(240) => 556, chr(241) => 556, - chr(242) => 556, chr(243) => 556, chr(244) => 556, chr(245) => 556, chr(246) => 556, chr(247) => 584, chr(248) => 611, chr(249) => 556, chr(250) => 556, chr(251) => 556, chr(252) => 556, chr(253) => 500, chr(254) => 556, chr(255) => 500]; +$cw = array( + chr(0)=>278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278, + chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>278,'"'=>355,'#'=>556,'$'=>556,'%'=>889,'&'=>667,'\''=>191,'('=>333,')'=>333,'*'=>389,'+'=>584, + ','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>278,';'=>278,'<'=>584,'='=>584,'>'=>584,'?'=>556,'@'=>1015,'A'=>667, + 'B'=>667,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>500,'K'=>667,'L'=>556,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944, + 'X'=>667,'Y'=>667,'Z'=>611,'['=>278,'\\'=>278,']'=>278,'^'=>469,'_'=>556,'`'=>333,'a'=>556,'b'=>556,'c'=>500,'d'=>556,'e'=>556,'f'=>278,'g'=>556,'h'=>556,'i'=>222,'j'=>222,'k'=>500,'l'=>222,'m'=>833, + 'n'=>556,'o'=>556,'p'=>556,'q'=>556,'r'=>333,'s'=>500,'t'=>278,'u'=>556,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>500,'{'=>334,'|'=>260,'}'=>334,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>222,chr(131)=>556, + chr(132)=>333,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>222,chr(146)=>222,chr(147)=>333,chr(148)=>333,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>500,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>260,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333, + chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>556,chr(182)=>537,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>667,chr(193)=>667,chr(194)=>667,chr(195)=>667,chr(196)=>667,chr(197)=>667, + chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>500,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>556,chr(241)=>556, + chr(242)=>556,chr(243)=>556,chr(244)=>556,chr(245)=>556,chr(246)=>556,chr(247)=>584,chr(248)=>611,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>500,chr(254)=>556,chr(255)=>500); $enc = 'cp1252'; -$uv = [0 => [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/helveticab.php b/app/ThirdParty/fpdf/font/helveticab.php index 3a9e482f..bcd73672 100644 --- a/app/ThirdParty/fpdf/font/helveticab.php +++ b/app/ThirdParty/fpdf/font/helveticab.php @@ -1,21 +1,21 @@ 278, chr(1) => 278, chr(2) => 278, chr(3) => 278, chr(4) => 278, chr(5) => 278, chr(6) => 278, chr(7) => 278, chr(8) => 278, chr(9) => 278, chr(10) => 278, chr(11) => 278, chr(12) => 278, chr(13) => 278, chr(14) => 278, chr(15) => 278, chr(16) => 278, chr(17) => 278, chr(18) => 278, chr(19) => 278, chr(20) => 278, chr(21) => 278, - chr(22) => 278, chr(23) => 278, chr(24) => 278, chr(25) => 278, chr(26) => 278, chr(27) => 278, chr(28) => 278, chr(29) => 278, chr(30) => 278, chr(31) => 278, ' ' => 278, '!' => 333, '"' => 474, '#' => 556, '$' => 556, '%' => 889, '&' => 722, '\'' => 238, '(' => 333, ')' => 333, '*' => 389, '+' => 584, - ',' => 278, '-' => 333, '.' => 278, '/' => 278, '0' => 556, '1' => 556, '2' => 556, '3' => 556, '4' => 556, '5' => 556, '6' => 556, '7' => 556, '8' => 556, '9' => 556, ':' => 333, ';' => 333, '<' => 584, '=' => 584, '>' => 584, '?' => 611, '@' => 975, 'A' => 722, - 'B' => 722, 'C' => 722, 'D' => 722, 'E' => 667, 'F' => 611, 'G' => 778, 'H' => 722, 'I' => 278, 'J' => 556, 'K' => 722, 'L' => 611, 'M' => 833, 'N' => 722, 'O' => 778, 'P' => 667, 'Q' => 778, 'R' => 722, 'S' => 667, 'T' => 611, 'U' => 722, 'V' => 667, 'W' => 944, - 'X' => 667, 'Y' => 667, 'Z' => 611, '[' => 333, '\\' => 278, ']' => 333, '^' => 584, '_' => 556, '`' => 333, 'a' => 556, 'b' => 611, 'c' => 556, 'd' => 611, 'e' => 556, 'f' => 333, 'g' => 611, 'h' => 611, 'i' => 278, 'j' => 278, 'k' => 556, 'l' => 278, 'm' => 889, - 'n' => 611, 'o' => 611, 'p' => 611, 'q' => 611, 'r' => 389, 's' => 556, 't' => 333, 'u' => 611, 'v' => 556, 'w' => 778, 'x' => 556, 'y' => 556, 'z' => 500, '{' => 389, '|' => 280, '}' => 389, '~' => 584, chr(127) => 350, chr(128) => 556, chr(129) => 350, chr(130) => 278, chr(131) => 556, - chr(132) => 500, chr(133) => 1000, chr(134) => 556, chr(135) => 556, chr(136) => 333, chr(137) => 1000, chr(138) => 667, chr(139) => 333, chr(140) => 1000, chr(141) => 350, chr(142) => 611, chr(143) => 350, chr(144) => 350, chr(145) => 278, chr(146) => 278, chr(147) => 500, chr(148) => 500, chr(149) => 350, chr(150) => 556, chr(151) => 1000, chr(152) => 333, chr(153) => 1000, - chr(154) => 556, chr(155) => 333, chr(156) => 944, chr(157) => 350, chr(158) => 500, chr(159) => 667, chr(160) => 278, chr(161) => 333, chr(162) => 556, chr(163) => 556, chr(164) => 556, chr(165) => 556, chr(166) => 280, chr(167) => 556, chr(168) => 333, chr(169) => 737, chr(170) => 370, chr(171) => 556, chr(172) => 584, chr(173) => 333, chr(174) => 737, chr(175) => 333, - chr(176) => 400, chr(177) => 584, chr(178) => 333, chr(179) => 333, chr(180) => 333, chr(181) => 611, chr(182) => 556, chr(183) => 278, chr(184) => 333, chr(185) => 333, chr(186) => 365, chr(187) => 556, chr(188) => 834, chr(189) => 834, chr(190) => 834, chr(191) => 611, chr(192) => 722, chr(193) => 722, chr(194) => 722, chr(195) => 722, chr(196) => 722, chr(197) => 722, - chr(198) => 1000, chr(199) => 722, chr(200) => 667, chr(201) => 667, chr(202) => 667, chr(203) => 667, chr(204) => 278, chr(205) => 278, chr(206) => 278, chr(207) => 278, chr(208) => 722, chr(209) => 722, chr(210) => 778, chr(211) => 778, chr(212) => 778, chr(213) => 778, chr(214) => 778, chr(215) => 584, chr(216) => 778, chr(217) => 722, chr(218) => 722, chr(219) => 722, - chr(220) => 722, chr(221) => 667, chr(222) => 667, chr(223) => 611, chr(224) => 556, chr(225) => 556, chr(226) => 556, chr(227) => 556, chr(228) => 556, chr(229) => 556, chr(230) => 889, chr(231) => 556, chr(232) => 556, chr(233) => 556, chr(234) => 556, chr(235) => 556, chr(236) => 278, chr(237) => 278, chr(238) => 278, chr(239) => 278, chr(240) => 611, chr(241) => 611, - chr(242) => 611, chr(243) => 611, chr(244) => 611, chr(245) => 611, chr(246) => 611, chr(247) => 584, chr(248) => 611, chr(249) => 611, chr(250) => 611, chr(251) => 611, chr(252) => 611, chr(253) => 556, chr(254) => 611, chr(255) => 556]; +$cw = array( + chr(0)=>278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278, + chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>333,'"'=>474,'#'=>556,'$'=>556,'%'=>889,'&'=>722,'\''=>238,'('=>333,')'=>333,'*'=>389,'+'=>584, + ','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>333,';'=>333,'<'=>584,'='=>584,'>'=>584,'?'=>611,'@'=>975,'A'=>722, + 'B'=>722,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>556,'K'=>722,'L'=>611,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944, + 'X'=>667,'Y'=>667,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>584,'_'=>556,'`'=>333,'a'=>556,'b'=>611,'c'=>556,'d'=>611,'e'=>556,'f'=>333,'g'=>611,'h'=>611,'i'=>278,'j'=>278,'k'=>556,'l'=>278,'m'=>889, + 'n'=>611,'o'=>611,'p'=>611,'q'=>611,'r'=>389,'s'=>556,'t'=>333,'u'=>611,'v'=>556,'w'=>778,'x'=>556,'y'=>556,'z'=>500,'{'=>389,'|'=>280,'}'=>389,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>278,chr(131)=>556, + chr(132)=>500,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>278,chr(146)=>278,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>556,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>280,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333, + chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>611,chr(182)=>556,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722, + chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>556,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>611,chr(241)=>611, + chr(242)=>611,chr(243)=>611,chr(244)=>611,chr(245)=>611,chr(246)=>611,chr(247)=>584,chr(248)=>611,chr(249)=>611,chr(250)=>611,chr(251)=>611,chr(252)=>611,chr(253)=>556,chr(254)=>611,chr(255)=>556); $enc = 'cp1252'; -$uv = [0 => [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/helveticabi.php b/app/ThirdParty/fpdf/font/helveticabi.php index 943017fb..0243cde4 100644 --- a/app/ThirdParty/fpdf/font/helveticabi.php +++ b/app/ThirdParty/fpdf/font/helveticabi.php @@ -1,21 +1,21 @@ 278, chr(1) => 278, chr(2) => 278, chr(3) => 278, chr(4) => 278, chr(5) => 278, chr(6) => 278, chr(7) => 278, chr(8) => 278, chr(9) => 278, chr(10) => 278, chr(11) => 278, chr(12) => 278, chr(13) => 278, chr(14) => 278, chr(15) => 278, chr(16) => 278, chr(17) => 278, chr(18) => 278, chr(19) => 278, chr(20) => 278, chr(21) => 278, - chr(22) => 278, chr(23) => 278, chr(24) => 278, chr(25) => 278, chr(26) => 278, chr(27) => 278, chr(28) => 278, chr(29) => 278, chr(30) => 278, chr(31) => 278, ' ' => 278, '!' => 333, '"' => 474, '#' => 556, '$' => 556, '%' => 889, '&' => 722, '\'' => 238, '(' => 333, ')' => 333, '*' => 389, '+' => 584, - ',' => 278, '-' => 333, '.' => 278, '/' => 278, '0' => 556, '1' => 556, '2' => 556, '3' => 556, '4' => 556, '5' => 556, '6' => 556, '7' => 556, '8' => 556, '9' => 556, ':' => 333, ';' => 333, '<' => 584, '=' => 584, '>' => 584, '?' => 611, '@' => 975, 'A' => 722, - 'B' => 722, 'C' => 722, 'D' => 722, 'E' => 667, 'F' => 611, 'G' => 778, 'H' => 722, 'I' => 278, 'J' => 556, 'K' => 722, 'L' => 611, 'M' => 833, 'N' => 722, 'O' => 778, 'P' => 667, 'Q' => 778, 'R' => 722, 'S' => 667, 'T' => 611, 'U' => 722, 'V' => 667, 'W' => 944, - 'X' => 667, 'Y' => 667, 'Z' => 611, '[' => 333, '\\' => 278, ']' => 333, '^' => 584, '_' => 556, '`' => 333, 'a' => 556, 'b' => 611, 'c' => 556, 'd' => 611, 'e' => 556, 'f' => 333, 'g' => 611, 'h' => 611, 'i' => 278, 'j' => 278, 'k' => 556, 'l' => 278, 'm' => 889, - 'n' => 611, 'o' => 611, 'p' => 611, 'q' => 611, 'r' => 389, 's' => 556, 't' => 333, 'u' => 611, 'v' => 556, 'w' => 778, 'x' => 556, 'y' => 556, 'z' => 500, '{' => 389, '|' => 280, '}' => 389, '~' => 584, chr(127) => 350, chr(128) => 556, chr(129) => 350, chr(130) => 278, chr(131) => 556, - chr(132) => 500, chr(133) => 1000, chr(134) => 556, chr(135) => 556, chr(136) => 333, chr(137) => 1000, chr(138) => 667, chr(139) => 333, chr(140) => 1000, chr(141) => 350, chr(142) => 611, chr(143) => 350, chr(144) => 350, chr(145) => 278, chr(146) => 278, chr(147) => 500, chr(148) => 500, chr(149) => 350, chr(150) => 556, chr(151) => 1000, chr(152) => 333, chr(153) => 1000, - chr(154) => 556, chr(155) => 333, chr(156) => 944, chr(157) => 350, chr(158) => 500, chr(159) => 667, chr(160) => 278, chr(161) => 333, chr(162) => 556, chr(163) => 556, chr(164) => 556, chr(165) => 556, chr(166) => 280, chr(167) => 556, chr(168) => 333, chr(169) => 737, chr(170) => 370, chr(171) => 556, chr(172) => 584, chr(173) => 333, chr(174) => 737, chr(175) => 333, - chr(176) => 400, chr(177) => 584, chr(178) => 333, chr(179) => 333, chr(180) => 333, chr(181) => 611, chr(182) => 556, chr(183) => 278, chr(184) => 333, chr(185) => 333, chr(186) => 365, chr(187) => 556, chr(188) => 834, chr(189) => 834, chr(190) => 834, chr(191) => 611, chr(192) => 722, chr(193) => 722, chr(194) => 722, chr(195) => 722, chr(196) => 722, chr(197) => 722, - chr(198) => 1000, chr(199) => 722, chr(200) => 667, chr(201) => 667, chr(202) => 667, chr(203) => 667, chr(204) => 278, chr(205) => 278, chr(206) => 278, chr(207) => 278, chr(208) => 722, chr(209) => 722, chr(210) => 778, chr(211) => 778, chr(212) => 778, chr(213) => 778, chr(214) => 778, chr(215) => 584, chr(216) => 778, chr(217) => 722, chr(218) => 722, chr(219) => 722, - chr(220) => 722, chr(221) => 667, chr(222) => 667, chr(223) => 611, chr(224) => 556, chr(225) => 556, chr(226) => 556, chr(227) => 556, chr(228) => 556, chr(229) => 556, chr(230) => 889, chr(231) => 556, chr(232) => 556, chr(233) => 556, chr(234) => 556, chr(235) => 556, chr(236) => 278, chr(237) => 278, chr(238) => 278, chr(239) => 278, chr(240) => 611, chr(241) => 611, - chr(242) => 611, chr(243) => 611, chr(244) => 611, chr(245) => 611, chr(246) => 611, chr(247) => 584, chr(248) => 611, chr(249) => 611, chr(250) => 611, chr(251) => 611, chr(252) => 611, chr(253) => 556, chr(254) => 611, chr(255) => 556]; +$cw = array( + chr(0)=>278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278, + chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>333,'"'=>474,'#'=>556,'$'=>556,'%'=>889,'&'=>722,'\''=>238,'('=>333,')'=>333,'*'=>389,'+'=>584, + ','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>333,';'=>333,'<'=>584,'='=>584,'>'=>584,'?'=>611,'@'=>975,'A'=>722, + 'B'=>722,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>556,'K'=>722,'L'=>611,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944, + 'X'=>667,'Y'=>667,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>584,'_'=>556,'`'=>333,'a'=>556,'b'=>611,'c'=>556,'d'=>611,'e'=>556,'f'=>333,'g'=>611,'h'=>611,'i'=>278,'j'=>278,'k'=>556,'l'=>278,'m'=>889, + 'n'=>611,'o'=>611,'p'=>611,'q'=>611,'r'=>389,'s'=>556,'t'=>333,'u'=>611,'v'=>556,'w'=>778,'x'=>556,'y'=>556,'z'=>500,'{'=>389,'|'=>280,'}'=>389,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>278,chr(131)=>556, + chr(132)=>500,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>278,chr(146)=>278,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>556,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>280,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333, + chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>611,chr(182)=>556,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722, + chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>556,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>611,chr(241)=>611, + chr(242)=>611,chr(243)=>611,chr(244)=>611,chr(245)=>611,chr(246)=>611,chr(247)=>584,chr(248)=>611,chr(249)=>611,chr(250)=>611,chr(251)=>611,chr(252)=>611,chr(253)=>556,chr(254)=>611,chr(255)=>556); $enc = 'cp1252'; -$uv = [0 => [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/helveticai.php b/app/ThirdParty/fpdf/font/helveticai.php index 5b05ec1a..06ec735b 100644 --- a/app/ThirdParty/fpdf/font/helveticai.php +++ b/app/ThirdParty/fpdf/font/helveticai.php @@ -1,21 +1,21 @@ 278, chr(1) => 278, chr(2) => 278, chr(3) => 278, chr(4) => 278, chr(5) => 278, chr(6) => 278, chr(7) => 278, chr(8) => 278, chr(9) => 278, chr(10) => 278, chr(11) => 278, chr(12) => 278, chr(13) => 278, chr(14) => 278, chr(15) => 278, chr(16) => 278, chr(17) => 278, chr(18) => 278, chr(19) => 278, chr(20) => 278, chr(21) => 278, - chr(22) => 278, chr(23) => 278, chr(24) => 278, chr(25) => 278, chr(26) => 278, chr(27) => 278, chr(28) => 278, chr(29) => 278, chr(30) => 278, chr(31) => 278, ' ' => 278, '!' => 278, '"' => 355, '#' => 556, '$' => 556, '%' => 889, '&' => 667, '\'' => 191, '(' => 333, ')' => 333, '*' => 389, '+' => 584, - ',' => 278, '-' => 333, '.' => 278, '/' => 278, '0' => 556, '1' => 556, '2' => 556, '3' => 556, '4' => 556, '5' => 556, '6' => 556, '7' => 556, '8' => 556, '9' => 556, ':' => 278, ';' => 278, '<' => 584, '=' => 584, '>' => 584, '?' => 556, '@' => 1015, 'A' => 667, - 'B' => 667, 'C' => 722, 'D' => 722, 'E' => 667, 'F' => 611, 'G' => 778, 'H' => 722, 'I' => 278, 'J' => 500, 'K' => 667, 'L' => 556, 'M' => 833, 'N' => 722, 'O' => 778, 'P' => 667, 'Q' => 778, 'R' => 722, 'S' => 667, 'T' => 611, 'U' => 722, 'V' => 667, 'W' => 944, - 'X' => 667, 'Y' => 667, 'Z' => 611, '[' => 278, '\\' => 278, ']' => 278, '^' => 469, '_' => 556, '`' => 333, 'a' => 556, 'b' => 556, 'c' => 500, 'd' => 556, 'e' => 556, 'f' => 278, 'g' => 556, 'h' => 556, 'i' => 222, 'j' => 222, 'k' => 500, 'l' => 222, 'm' => 833, - 'n' => 556, 'o' => 556, 'p' => 556, 'q' => 556, 'r' => 333, 's' => 500, 't' => 278, 'u' => 556, 'v' => 500, 'w' => 722, 'x' => 500, 'y' => 500, 'z' => 500, '{' => 334, '|' => 260, '}' => 334, '~' => 584, chr(127) => 350, chr(128) => 556, chr(129) => 350, chr(130) => 222, chr(131) => 556, - chr(132) => 333, chr(133) => 1000, chr(134) => 556, chr(135) => 556, chr(136) => 333, chr(137) => 1000, chr(138) => 667, chr(139) => 333, chr(140) => 1000, chr(141) => 350, chr(142) => 611, chr(143) => 350, chr(144) => 350, chr(145) => 222, chr(146) => 222, chr(147) => 333, chr(148) => 333, chr(149) => 350, chr(150) => 556, chr(151) => 1000, chr(152) => 333, chr(153) => 1000, - chr(154) => 500, chr(155) => 333, chr(156) => 944, chr(157) => 350, chr(158) => 500, chr(159) => 667, chr(160) => 278, chr(161) => 333, chr(162) => 556, chr(163) => 556, chr(164) => 556, chr(165) => 556, chr(166) => 260, chr(167) => 556, chr(168) => 333, chr(169) => 737, chr(170) => 370, chr(171) => 556, chr(172) => 584, chr(173) => 333, chr(174) => 737, chr(175) => 333, - chr(176) => 400, chr(177) => 584, chr(178) => 333, chr(179) => 333, chr(180) => 333, chr(181) => 556, chr(182) => 537, chr(183) => 278, chr(184) => 333, chr(185) => 333, chr(186) => 365, chr(187) => 556, chr(188) => 834, chr(189) => 834, chr(190) => 834, chr(191) => 611, chr(192) => 667, chr(193) => 667, chr(194) => 667, chr(195) => 667, chr(196) => 667, chr(197) => 667, - chr(198) => 1000, chr(199) => 722, chr(200) => 667, chr(201) => 667, chr(202) => 667, chr(203) => 667, chr(204) => 278, chr(205) => 278, chr(206) => 278, chr(207) => 278, chr(208) => 722, chr(209) => 722, chr(210) => 778, chr(211) => 778, chr(212) => 778, chr(213) => 778, chr(214) => 778, chr(215) => 584, chr(216) => 778, chr(217) => 722, chr(218) => 722, chr(219) => 722, - chr(220) => 722, chr(221) => 667, chr(222) => 667, chr(223) => 611, chr(224) => 556, chr(225) => 556, chr(226) => 556, chr(227) => 556, chr(228) => 556, chr(229) => 556, chr(230) => 889, chr(231) => 500, chr(232) => 556, chr(233) => 556, chr(234) => 556, chr(235) => 556, chr(236) => 278, chr(237) => 278, chr(238) => 278, chr(239) => 278, chr(240) => 556, chr(241) => 556, - chr(242) => 556, chr(243) => 556, chr(244) => 556, chr(245) => 556, chr(246) => 556, chr(247) => 584, chr(248) => 611, chr(249) => 556, chr(250) => 556, chr(251) => 556, chr(252) => 556, chr(253) => 500, chr(254) => 556, chr(255) => 500]; +$cw = array( + chr(0)=>278,chr(1)=>278,chr(2)=>278,chr(3)=>278,chr(4)=>278,chr(5)=>278,chr(6)=>278,chr(7)=>278,chr(8)=>278,chr(9)=>278,chr(10)=>278,chr(11)=>278,chr(12)=>278,chr(13)=>278,chr(14)=>278,chr(15)=>278,chr(16)=>278,chr(17)=>278,chr(18)=>278,chr(19)=>278,chr(20)=>278,chr(21)=>278, + chr(22)=>278,chr(23)=>278,chr(24)=>278,chr(25)=>278,chr(26)=>278,chr(27)=>278,chr(28)=>278,chr(29)=>278,chr(30)=>278,chr(31)=>278,' '=>278,'!'=>278,'"'=>355,'#'=>556,'$'=>556,'%'=>889,'&'=>667,'\''=>191,'('=>333,')'=>333,'*'=>389,'+'=>584, + ','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>278,';'=>278,'<'=>584,'='=>584,'>'=>584,'?'=>556,'@'=>1015,'A'=>667, + 'B'=>667,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>500,'K'=>667,'L'=>556,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944, + 'X'=>667,'Y'=>667,'Z'=>611,'['=>278,'\\'=>278,']'=>278,'^'=>469,'_'=>556,'`'=>333,'a'=>556,'b'=>556,'c'=>500,'d'=>556,'e'=>556,'f'=>278,'g'=>556,'h'=>556,'i'=>222,'j'=>222,'k'=>500,'l'=>222,'m'=>833, + 'n'=>556,'o'=>556,'p'=>556,'q'=>556,'r'=>333,'s'=>500,'t'=>278,'u'=>556,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>500,'{'=>334,'|'=>260,'}'=>334,'~'=>584,chr(127)=>350,chr(128)=>556,chr(129)=>350,chr(130)=>222,chr(131)=>556, + chr(132)=>333,chr(133)=>1000,chr(134)=>556,chr(135)=>556,chr(136)=>333,chr(137)=>1000,chr(138)=>667,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>222,chr(146)=>222,chr(147)=>333,chr(148)=>333,chr(149)=>350,chr(150)=>556,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>500,chr(155)=>333,chr(156)=>944,chr(157)=>350,chr(158)=>500,chr(159)=>667,chr(160)=>278,chr(161)=>333,chr(162)=>556,chr(163)=>556,chr(164)=>556,chr(165)=>556,chr(166)=>260,chr(167)=>556,chr(168)=>333,chr(169)=>737,chr(170)=>370,chr(171)=>556,chr(172)=>584,chr(173)=>333,chr(174)=>737,chr(175)=>333, + chr(176)=>400,chr(177)=>584,chr(178)=>333,chr(179)=>333,chr(180)=>333,chr(181)=>556,chr(182)=>537,chr(183)=>278,chr(184)=>333,chr(185)=>333,chr(186)=>365,chr(187)=>556,chr(188)=>834,chr(189)=>834,chr(190)=>834,chr(191)=>611,chr(192)=>667,chr(193)=>667,chr(194)=>667,chr(195)=>667,chr(196)=>667,chr(197)=>667, + chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>278,chr(205)=>278,chr(206)=>278,chr(207)=>278,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>584,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>667,chr(222)=>667,chr(223)=>611,chr(224)=>556,chr(225)=>556,chr(226)=>556,chr(227)=>556,chr(228)=>556,chr(229)=>556,chr(230)=>889,chr(231)=>500,chr(232)=>556,chr(233)=>556,chr(234)=>556,chr(235)=>556,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>556,chr(241)=>556, + chr(242)=>556,chr(243)=>556,chr(244)=>556,chr(245)=>556,chr(246)=>556,chr(247)=>584,chr(248)=>611,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>500,chr(254)=>556,chr(255)=>500); $enc = 'cp1252'; -$uv = [0 => [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/symbol.php b/app/ThirdParty/fpdf/font/symbol.php index 8580057f..f8f0c330 100644 --- a/app/ThirdParty/fpdf/font/symbol.php +++ b/app/ThirdParty/fpdf/font/symbol.php @@ -1,20 +1,20 @@ 250, chr(1) => 250, chr(2) => 250, chr(3) => 250, chr(4) => 250, chr(5) => 250, chr(6) => 250, chr(7) => 250, chr(8) => 250, chr(9) => 250, chr(10) => 250, chr(11) => 250, chr(12) => 250, chr(13) => 250, chr(14) => 250, chr(15) => 250, chr(16) => 250, chr(17) => 250, chr(18) => 250, chr(19) => 250, chr(20) => 250, chr(21) => 250, - chr(22) => 250, chr(23) => 250, chr(24) => 250, chr(25) => 250, chr(26) => 250, chr(27) => 250, chr(28) => 250, chr(29) => 250, chr(30) => 250, chr(31) => 250, ' ' => 250, '!' => 333, '"' => 713, '#' => 500, '$' => 549, '%' => 833, '&' => 778, '\'' => 439, '(' => 333, ')' => 333, '*' => 500, '+' => 549, - ',' => 250, '-' => 549, '.' => 250, '/' => 278, '0' => 500, '1' => 500, '2' => 500, '3' => 500, '4' => 500, '5' => 500, '6' => 500, '7' => 500, '8' => 500, '9' => 500, ':' => 278, ';' => 278, '<' => 549, '=' => 549, '>' => 549, '?' => 444, '@' => 549, 'A' => 722, - 'B' => 667, 'C' => 722, 'D' => 612, 'E' => 611, 'F' => 763, 'G' => 603, 'H' => 722, 'I' => 333, 'J' => 631, 'K' => 722, 'L' => 686, 'M' => 889, 'N' => 722, 'O' => 722, 'P' => 768, 'Q' => 741, 'R' => 556, 'S' => 592, 'T' => 611, 'U' => 690, 'V' => 439, 'W' => 768, - 'X' => 645, 'Y' => 795, 'Z' => 611, '[' => 333, '\\' => 863, ']' => 333, '^' => 658, '_' => 500, '`' => 500, 'a' => 631, 'b' => 549, 'c' => 549, 'd' => 494, 'e' => 439, 'f' => 521, 'g' => 411, 'h' => 603, 'i' => 329, 'j' => 603, 'k' => 549, 'l' => 549, 'm' => 576, - 'n' => 521, 'o' => 549, 'p' => 549, 'q' => 521, 'r' => 549, 's' => 603, 't' => 439, 'u' => 576, 'v' => 713, 'w' => 686, 'x' => 493, 'y' => 686, 'z' => 494, '{' => 480, '|' => 200, '}' => 480, '~' => 549, chr(127) => 0, chr(128) => 0, chr(129) => 0, chr(130) => 0, chr(131) => 0, - chr(132) => 0, chr(133) => 0, chr(134) => 0, chr(135) => 0, chr(136) => 0, chr(137) => 0, chr(138) => 0, chr(139) => 0, chr(140) => 0, chr(141) => 0, chr(142) => 0, chr(143) => 0, chr(144) => 0, chr(145) => 0, chr(146) => 0, chr(147) => 0, chr(148) => 0, chr(149) => 0, chr(150) => 0, chr(151) => 0, chr(152) => 0, chr(153) => 0, - chr(154) => 0, chr(155) => 0, chr(156) => 0, chr(157) => 0, chr(158) => 0, chr(159) => 0, chr(160) => 750, chr(161) => 620, chr(162) => 247, chr(163) => 549, chr(164) => 167, chr(165) => 713, chr(166) => 500, chr(167) => 753, chr(168) => 753, chr(169) => 753, chr(170) => 753, chr(171) => 1042, chr(172) => 987, chr(173) => 603, chr(174) => 987, chr(175) => 603, - chr(176) => 400, chr(177) => 549, chr(178) => 411, chr(179) => 549, chr(180) => 549, chr(181) => 713, chr(182) => 494, chr(183) => 460, chr(184) => 549, chr(185) => 549, chr(186) => 549, chr(187) => 549, chr(188) => 1000, chr(189) => 603, chr(190) => 1000, chr(191) => 658, chr(192) => 823, chr(193) => 686, chr(194) => 795, chr(195) => 987, chr(196) => 768, chr(197) => 768, - chr(198) => 823, chr(199) => 768, chr(200) => 768, chr(201) => 713, chr(202) => 713, chr(203) => 713, chr(204) => 713, chr(205) => 713, chr(206) => 713, chr(207) => 713, chr(208) => 768, chr(209) => 713, chr(210) => 790, chr(211) => 790, chr(212) => 890, chr(213) => 823, chr(214) => 549, chr(215) => 250, chr(216) => 713, chr(217) => 603, chr(218) => 603, chr(219) => 1042, - chr(220) => 987, chr(221) => 603, chr(222) => 987, chr(223) => 603, chr(224) => 494, chr(225) => 329, chr(226) => 790, chr(227) => 790, chr(228) => 786, chr(229) => 713, chr(230) => 384, chr(231) => 384, chr(232) => 384, chr(233) => 384, chr(234) => 384, chr(235) => 384, chr(236) => 494, chr(237) => 494, chr(238) => 494, chr(239) => 494, chr(240) => 0, chr(241) => 329, - chr(242) => 274, chr(243) => 686, chr(244) => 686, chr(245) => 686, chr(246) => 384, chr(247) => 384, chr(248) => 384, chr(249) => 384, chr(250) => 384, chr(251) => 384, chr(252) => 494, chr(253) => 494, chr(254) => 494, chr(255) => 0]; -$uv = [32 => 160, 33 => 33, 34 => 8704, 35 => 35, 36 => 8707, 37 => [37, 2], 39 => 8715, 40 => [40, 2], 42 => 8727, 43 => [43, 2], 45 => 8722, 46 => [46, 18], 64 => 8773, 65 => [913, 2], 67 => 935, 68 => [916, 2], 70 => 934, 71 => 915, 72 => 919, 73 => 921, 74 => 977, 75 => [922, 4], 79 => [927, 2], 81 => 920, 82 => 929, 83 => [931, 3], 86 => 962, 87 => 937, 88 => 926, 89 => 936, 90 => 918, 91 => 91, 92 => 8756, 93 => 93, 94 => 8869, 95 => 95, 96 => 63717, 97 => [945, 2], 99 => 967, 100 => [948, 2], 102 => 966, 103 => 947, 104 => 951, 105 => 953, 106 => 981, 107 => [954, 4], 111 => [959, 2], 113 => 952, 114 => 961, 115 => [963, 3], 118 => 982, 119 => 969, 120 => 958, 121 => 968, 122 => 950, 123 => [123, 3], 126 => 8764, 160 => 8364, 161 => 978, 162 => 8242, 163 => 8804, 164 => 8725, 165 => 8734, 166 => 402, 167 => 9827, 168 => 9830, 169 => 9829, 170 => 9824, 171 => 8596, 172 => [8592, 4], 176 => [176, 2], 178 => 8243, 179 => 8805, 180 => 215, 181 => 8733, 182 => 8706, 183 => 8226, 184 => 247, 185 => [8800, 2], 187 => 8776, 188 => 8230, 189 => [63718, 2], 191 => 8629, 192 => 8501, 193 => 8465, 194 => 8476, 195 => 8472, 196 => 8855, 197 => 8853, 198 => 8709, 199 => [8745, 2], 201 => 8835, 202 => 8839, 203 => 8836, 204 => 8834, 205 => 8838, 206 => [8712, 2], 208 => 8736, 209 => 8711, 210 => 63194, 211 => 63193, 212 => 63195, 213 => 8719, 214 => 8730, 215 => 8901, 216 => 172, 217 => [8743, 2], 219 => 8660, 220 => [8656, 4], 224 => 9674, 225 => 9001, 226 => [63720, 3], 229 => 8721, 230 => [63723, 10], 241 => 9002, 242 => 8747, 243 => 8992, 244 => 63733, 245 => 8993, 246 => [63734, 9]]; +$cw = array( + chr(0)=>250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250, + chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>713,'#'=>500,'$'=>549,'%'=>833,'&'=>778,'\''=>439,'('=>333,')'=>333,'*'=>500,'+'=>549, + ','=>250,'-'=>549,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>278,';'=>278,'<'=>549,'='=>549,'>'=>549,'?'=>444,'@'=>549,'A'=>722, + 'B'=>667,'C'=>722,'D'=>612,'E'=>611,'F'=>763,'G'=>603,'H'=>722,'I'=>333,'J'=>631,'K'=>722,'L'=>686,'M'=>889,'N'=>722,'O'=>722,'P'=>768,'Q'=>741,'R'=>556,'S'=>592,'T'=>611,'U'=>690,'V'=>439,'W'=>768, + 'X'=>645,'Y'=>795,'Z'=>611,'['=>333,'\\'=>863,']'=>333,'^'=>658,'_'=>500,'`'=>500,'a'=>631,'b'=>549,'c'=>549,'d'=>494,'e'=>439,'f'=>521,'g'=>411,'h'=>603,'i'=>329,'j'=>603,'k'=>549,'l'=>549,'m'=>576, + 'n'=>521,'o'=>549,'p'=>549,'q'=>521,'r'=>549,'s'=>603,'t'=>439,'u'=>576,'v'=>713,'w'=>686,'x'=>493,'y'=>686,'z'=>494,'{'=>480,'|'=>200,'}'=>480,'~'=>549,chr(127)=>0,chr(128)=>0,chr(129)=>0,chr(130)=>0,chr(131)=>0, + chr(132)=>0,chr(133)=>0,chr(134)=>0,chr(135)=>0,chr(136)=>0,chr(137)=>0,chr(138)=>0,chr(139)=>0,chr(140)=>0,chr(141)=>0,chr(142)=>0,chr(143)=>0,chr(144)=>0,chr(145)=>0,chr(146)=>0,chr(147)=>0,chr(148)=>0,chr(149)=>0,chr(150)=>0,chr(151)=>0,chr(152)=>0,chr(153)=>0, + chr(154)=>0,chr(155)=>0,chr(156)=>0,chr(157)=>0,chr(158)=>0,chr(159)=>0,chr(160)=>750,chr(161)=>620,chr(162)=>247,chr(163)=>549,chr(164)=>167,chr(165)=>713,chr(166)=>500,chr(167)=>753,chr(168)=>753,chr(169)=>753,chr(170)=>753,chr(171)=>1042,chr(172)=>987,chr(173)=>603,chr(174)=>987,chr(175)=>603, + chr(176)=>400,chr(177)=>549,chr(178)=>411,chr(179)=>549,chr(180)=>549,chr(181)=>713,chr(182)=>494,chr(183)=>460,chr(184)=>549,chr(185)=>549,chr(186)=>549,chr(187)=>549,chr(188)=>1000,chr(189)=>603,chr(190)=>1000,chr(191)=>658,chr(192)=>823,chr(193)=>686,chr(194)=>795,chr(195)=>987,chr(196)=>768,chr(197)=>768, + chr(198)=>823,chr(199)=>768,chr(200)=>768,chr(201)=>713,chr(202)=>713,chr(203)=>713,chr(204)=>713,chr(205)=>713,chr(206)=>713,chr(207)=>713,chr(208)=>768,chr(209)=>713,chr(210)=>790,chr(211)=>790,chr(212)=>890,chr(213)=>823,chr(214)=>549,chr(215)=>250,chr(216)=>713,chr(217)=>603,chr(218)=>603,chr(219)=>1042, + chr(220)=>987,chr(221)=>603,chr(222)=>987,chr(223)=>603,chr(224)=>494,chr(225)=>329,chr(226)=>790,chr(227)=>790,chr(228)=>786,chr(229)=>713,chr(230)=>384,chr(231)=>384,chr(232)=>384,chr(233)=>384,chr(234)=>384,chr(235)=>384,chr(236)=>494,chr(237)=>494,chr(238)=>494,chr(239)=>494,chr(240)=>0,chr(241)=>329, + chr(242)=>274,chr(243)=>686,chr(244)=>686,chr(245)=>686,chr(246)=>384,chr(247)=>384,chr(248)=>384,chr(249)=>384,chr(250)=>384,chr(251)=>384,chr(252)=>494,chr(253)=>494,chr(254)=>494,chr(255)=>0); +$uv = array(32=>160,33=>33,34=>8704,35=>35,36=>8707,37=>array(37,2),39=>8715,40=>array(40,2),42=>8727,43=>array(43,2),45=>8722,46=>array(46,18),64=>8773,65=>array(913,2),67=>935,68=>array(916,2),70=>934,71=>915,72=>919,73=>921,74=>977,75=>array(922,4),79=>array(927,2),81=>920,82=>929,83=>array(931,3),86=>962,87=>937,88=>926,89=>936,90=>918,91=>91,92=>8756,93=>93,94=>8869,95=>95,96=>63717,97=>array(945,2),99=>967,100=>array(948,2),102=>966,103=>947,104=>951,105=>953,106=>981,107=>array(954,4),111=>array(959,2),113=>952,114=>961,115=>array(963,3),118=>982,119=>969,120=>958,121=>968,122=>950,123=>array(123,3),126=>8764,160=>8364,161=>978,162=>8242,163=>8804,164=>8725,165=>8734,166=>402,167=>9827,168=>9830,169=>9829,170=>9824,171=>8596,172=>array(8592,4),176=>array(176,2),178=>8243,179=>8805,180=>215,181=>8733,182=>8706,183=>8226,184=>247,185=>array(8800,2),187=>8776,188=>8230,189=>array(63718,2),191=>8629,192=>8501,193=>8465,194=>8476,195=>8472,196=>8855,197=>8853,198=>8709,199=>array(8745,2),201=>8835,202=>8839,203=>8836,204=>8834,205=>8838,206=>array(8712,2),208=>8736,209=>8711,210=>63194,211=>63193,212=>63195,213=>8719,214=>8730,215=>8901,216=>172,217=>array(8743,2),219=>8660,220=>array(8656,4),224=>9674,225=>9001,226=>array(63720,3),229=>8721,230=>array(63723,10),241=>9002,242=>8747,243=>8992,244=>63733,245=>8993,246=>array(63734,9)); +?> diff --git a/app/ThirdParty/fpdf/font/times.php b/app/ThirdParty/fpdf/font/times.php index 68170a03..81f2a8b4 100644 --- a/app/ThirdParty/fpdf/font/times.php +++ b/app/ThirdParty/fpdf/font/times.php @@ -1,21 +1,21 @@ 250, chr(1) => 250, chr(2) => 250, chr(3) => 250, chr(4) => 250, chr(5) => 250, chr(6) => 250, chr(7) => 250, chr(8) => 250, chr(9) => 250, chr(10) => 250, chr(11) => 250, chr(12) => 250, chr(13) => 250, chr(14) => 250, chr(15) => 250, chr(16) => 250, chr(17) => 250, chr(18) => 250, chr(19) => 250, chr(20) => 250, chr(21) => 250, - chr(22) => 250, chr(23) => 250, chr(24) => 250, chr(25) => 250, chr(26) => 250, chr(27) => 250, chr(28) => 250, chr(29) => 250, chr(30) => 250, chr(31) => 250, ' ' => 250, '!' => 333, '"' => 408, '#' => 500, '$' => 500, '%' => 833, '&' => 778, '\'' => 180, '(' => 333, ')' => 333, '*' => 500, '+' => 564, - ',' => 250, '-' => 333, '.' => 250, '/' => 278, '0' => 500, '1' => 500, '2' => 500, '3' => 500, '4' => 500, '5' => 500, '6' => 500, '7' => 500, '8' => 500, '9' => 500, ':' => 278, ';' => 278, '<' => 564, '=' => 564, '>' => 564, '?' => 444, '@' => 921, 'A' => 722, - 'B' => 667, 'C' => 667, 'D' => 722, 'E' => 611, 'F' => 556, 'G' => 722, 'H' => 722, 'I' => 333, 'J' => 389, 'K' => 722, 'L' => 611, 'M' => 889, 'N' => 722, 'O' => 722, 'P' => 556, 'Q' => 722, 'R' => 667, 'S' => 556, 'T' => 611, 'U' => 722, 'V' => 722, 'W' => 944, - 'X' => 722, 'Y' => 722, 'Z' => 611, '[' => 333, '\\' => 278, ']' => 333, '^' => 469, '_' => 500, '`' => 333, 'a' => 444, 'b' => 500, 'c' => 444, 'd' => 500, 'e' => 444, 'f' => 333, 'g' => 500, 'h' => 500, 'i' => 278, 'j' => 278, 'k' => 500, 'l' => 278, 'm' => 778, - 'n' => 500, 'o' => 500, 'p' => 500, 'q' => 500, 'r' => 333, 's' => 389, 't' => 278, 'u' => 500, 'v' => 500, 'w' => 722, 'x' => 500, 'y' => 500, 'z' => 444, '{' => 480, '|' => 200, '}' => 480, '~' => 541, chr(127) => 350, chr(128) => 500, chr(129) => 350, chr(130) => 333, chr(131) => 500, - chr(132) => 444, chr(133) => 1000, chr(134) => 500, chr(135) => 500, chr(136) => 333, chr(137) => 1000, chr(138) => 556, chr(139) => 333, chr(140) => 889, chr(141) => 350, chr(142) => 611, chr(143) => 350, chr(144) => 350, chr(145) => 333, chr(146) => 333, chr(147) => 444, chr(148) => 444, chr(149) => 350, chr(150) => 500, chr(151) => 1000, chr(152) => 333, chr(153) => 980, - chr(154) => 389, chr(155) => 333, chr(156) => 722, chr(157) => 350, chr(158) => 444, chr(159) => 722, chr(160) => 250, chr(161) => 333, chr(162) => 500, chr(163) => 500, chr(164) => 500, chr(165) => 500, chr(166) => 200, chr(167) => 500, chr(168) => 333, chr(169) => 760, chr(170) => 276, chr(171) => 500, chr(172) => 564, chr(173) => 333, chr(174) => 760, chr(175) => 333, - chr(176) => 400, chr(177) => 564, chr(178) => 300, chr(179) => 300, chr(180) => 333, chr(181) => 500, chr(182) => 453, chr(183) => 250, chr(184) => 333, chr(185) => 300, chr(186) => 310, chr(187) => 500, chr(188) => 750, chr(189) => 750, chr(190) => 750, chr(191) => 444, chr(192) => 722, chr(193) => 722, chr(194) => 722, chr(195) => 722, chr(196) => 722, chr(197) => 722, - chr(198) => 889, chr(199) => 667, chr(200) => 611, chr(201) => 611, chr(202) => 611, chr(203) => 611, chr(204) => 333, chr(205) => 333, chr(206) => 333, chr(207) => 333, chr(208) => 722, chr(209) => 722, chr(210) => 722, chr(211) => 722, chr(212) => 722, chr(213) => 722, chr(214) => 722, chr(215) => 564, chr(216) => 722, chr(217) => 722, chr(218) => 722, chr(219) => 722, - chr(220) => 722, chr(221) => 722, chr(222) => 556, chr(223) => 500, chr(224) => 444, chr(225) => 444, chr(226) => 444, chr(227) => 444, chr(228) => 444, chr(229) => 444, chr(230) => 667, chr(231) => 444, chr(232) => 444, chr(233) => 444, chr(234) => 444, chr(235) => 444, chr(236) => 278, chr(237) => 278, chr(238) => 278, chr(239) => 278, chr(240) => 500, chr(241) => 500, - chr(242) => 500, chr(243) => 500, chr(244) => 500, chr(245) => 500, chr(246) => 500, chr(247) => 564, chr(248) => 500, chr(249) => 500, chr(250) => 500, chr(251) => 500, chr(252) => 500, chr(253) => 500, chr(254) => 500, chr(255) => 500]; +$cw = array( + chr(0)=>250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250, + chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>408,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>180,'('=>333,')'=>333,'*'=>500,'+'=>564, + ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>278,';'=>278,'<'=>564,'='=>564,'>'=>564,'?'=>444,'@'=>921,'A'=>722, + 'B'=>667,'C'=>667,'D'=>722,'E'=>611,'F'=>556,'G'=>722,'H'=>722,'I'=>333,'J'=>389,'K'=>722,'L'=>611,'M'=>889,'N'=>722,'O'=>722,'P'=>556,'Q'=>722,'R'=>667,'S'=>556,'T'=>611,'U'=>722,'V'=>722,'W'=>944, + 'X'=>722,'Y'=>722,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>469,'_'=>500,'`'=>333,'a'=>444,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>333,'g'=>500,'h'=>500,'i'=>278,'j'=>278,'k'=>500,'l'=>278,'m'=>778, + 'n'=>500,'o'=>500,'p'=>500,'q'=>500,'r'=>333,'s'=>389,'t'=>278,'u'=>500,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>444,'{'=>480,'|'=>200,'}'=>480,'~'=>541,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500, + chr(132)=>444,chr(133)=>1000,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>556,chr(139)=>333,chr(140)=>889,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>444,chr(148)=>444,chr(149)=>350,chr(150)=>500,chr(151)=>1000,chr(152)=>333,chr(153)=>980, + chr(154)=>389,chr(155)=>333,chr(156)=>722,chr(157)=>350,chr(158)=>444,chr(159)=>722,chr(160)=>250,chr(161)=>333,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>200,chr(167)=>500,chr(168)=>333,chr(169)=>760,chr(170)=>276,chr(171)=>500,chr(172)=>564,chr(173)=>333,chr(174)=>760,chr(175)=>333, + chr(176)=>400,chr(177)=>564,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>500,chr(182)=>453,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>310,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>444,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722, + chr(198)=>889,chr(199)=>667,chr(200)=>611,chr(201)=>611,chr(202)=>611,chr(203)=>611,chr(204)=>333,chr(205)=>333,chr(206)=>333,chr(207)=>333,chr(208)=>722,chr(209)=>722,chr(210)=>722,chr(211)=>722,chr(212)=>722,chr(213)=>722,chr(214)=>722,chr(215)=>564,chr(216)=>722,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>722,chr(222)=>556,chr(223)=>500,chr(224)=>444,chr(225)=>444,chr(226)=>444,chr(227)=>444,chr(228)=>444,chr(229)=>444,chr(230)=>667,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>500, + chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>564,chr(248)=>500,chr(249)=>500,chr(250)=>500,chr(251)=>500,chr(252)=>500,chr(253)=>500,chr(254)=>500,chr(255)=>500); $enc = 'cp1252'; -$uv = [0 => [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/timesb.php b/app/ThirdParty/fpdf/font/timesb.php index 3f689ac9..7db704fd 100644 --- a/app/ThirdParty/fpdf/font/timesb.php +++ b/app/ThirdParty/fpdf/font/timesb.php @@ -1,21 +1,21 @@ 250, chr(1) => 250, chr(2) => 250, chr(3) => 250, chr(4) => 250, chr(5) => 250, chr(6) => 250, chr(7) => 250, chr(8) => 250, chr(9) => 250, chr(10) => 250, chr(11) => 250, chr(12) => 250, chr(13) => 250, chr(14) => 250, chr(15) => 250, chr(16) => 250, chr(17) => 250, chr(18) => 250, chr(19) => 250, chr(20) => 250, chr(21) => 250, - chr(22) => 250, chr(23) => 250, chr(24) => 250, chr(25) => 250, chr(26) => 250, chr(27) => 250, chr(28) => 250, chr(29) => 250, chr(30) => 250, chr(31) => 250, ' ' => 250, '!' => 333, '"' => 555, '#' => 500, '$' => 500, '%' => 1000, '&' => 833, '\'' => 278, '(' => 333, ')' => 333, '*' => 500, '+' => 570, - ',' => 250, '-' => 333, '.' => 250, '/' => 278, '0' => 500, '1' => 500, '2' => 500, '3' => 500, '4' => 500, '5' => 500, '6' => 500, '7' => 500, '8' => 500, '9' => 500, ':' => 333, ';' => 333, '<' => 570, '=' => 570, '>' => 570, '?' => 500, '@' => 930, 'A' => 722, - 'B' => 667, 'C' => 722, 'D' => 722, 'E' => 667, 'F' => 611, 'G' => 778, 'H' => 778, 'I' => 389, 'J' => 500, 'K' => 778, 'L' => 667, 'M' => 944, 'N' => 722, 'O' => 778, 'P' => 611, 'Q' => 778, 'R' => 722, 'S' => 556, 'T' => 667, 'U' => 722, 'V' => 722, 'W' => 1000, - 'X' => 722, 'Y' => 722, 'Z' => 667, '[' => 333, '\\' => 278, ']' => 333, '^' => 581, '_' => 500, '`' => 333, 'a' => 500, 'b' => 556, 'c' => 444, 'd' => 556, 'e' => 444, 'f' => 333, 'g' => 500, 'h' => 556, 'i' => 278, 'j' => 333, 'k' => 556, 'l' => 278, 'm' => 833, - 'n' => 556, 'o' => 500, 'p' => 556, 'q' => 556, 'r' => 444, 's' => 389, 't' => 333, 'u' => 556, 'v' => 500, 'w' => 722, 'x' => 500, 'y' => 500, 'z' => 444, '{' => 394, '|' => 220, '}' => 394, '~' => 520, chr(127) => 350, chr(128) => 500, chr(129) => 350, chr(130) => 333, chr(131) => 500, - chr(132) => 500, chr(133) => 1000, chr(134) => 500, chr(135) => 500, chr(136) => 333, chr(137) => 1000, chr(138) => 556, chr(139) => 333, chr(140) => 1000, chr(141) => 350, chr(142) => 667, chr(143) => 350, chr(144) => 350, chr(145) => 333, chr(146) => 333, chr(147) => 500, chr(148) => 500, chr(149) => 350, chr(150) => 500, chr(151) => 1000, chr(152) => 333, chr(153) => 1000, - chr(154) => 389, chr(155) => 333, chr(156) => 722, chr(157) => 350, chr(158) => 444, chr(159) => 722, chr(160) => 250, chr(161) => 333, chr(162) => 500, chr(163) => 500, chr(164) => 500, chr(165) => 500, chr(166) => 220, chr(167) => 500, chr(168) => 333, chr(169) => 747, chr(170) => 300, chr(171) => 500, chr(172) => 570, chr(173) => 333, chr(174) => 747, chr(175) => 333, - chr(176) => 400, chr(177) => 570, chr(178) => 300, chr(179) => 300, chr(180) => 333, chr(181) => 556, chr(182) => 540, chr(183) => 250, chr(184) => 333, chr(185) => 300, chr(186) => 330, chr(187) => 500, chr(188) => 750, chr(189) => 750, chr(190) => 750, chr(191) => 500, chr(192) => 722, chr(193) => 722, chr(194) => 722, chr(195) => 722, chr(196) => 722, chr(197) => 722, - chr(198) => 1000, chr(199) => 722, chr(200) => 667, chr(201) => 667, chr(202) => 667, chr(203) => 667, chr(204) => 389, chr(205) => 389, chr(206) => 389, chr(207) => 389, chr(208) => 722, chr(209) => 722, chr(210) => 778, chr(211) => 778, chr(212) => 778, chr(213) => 778, chr(214) => 778, chr(215) => 570, chr(216) => 778, chr(217) => 722, chr(218) => 722, chr(219) => 722, - chr(220) => 722, chr(221) => 722, chr(222) => 611, chr(223) => 556, chr(224) => 500, chr(225) => 500, chr(226) => 500, chr(227) => 500, chr(228) => 500, chr(229) => 500, chr(230) => 722, chr(231) => 444, chr(232) => 444, chr(233) => 444, chr(234) => 444, chr(235) => 444, chr(236) => 278, chr(237) => 278, chr(238) => 278, chr(239) => 278, chr(240) => 500, chr(241) => 556, - chr(242) => 500, chr(243) => 500, chr(244) => 500, chr(245) => 500, chr(246) => 500, chr(247) => 570, chr(248) => 500, chr(249) => 556, chr(250) => 556, chr(251) => 556, chr(252) => 556, chr(253) => 500, chr(254) => 556, chr(255) => 500]; +$cw = array( + chr(0)=>250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250, + chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>555,'#'=>500,'$'=>500,'%'=>1000,'&'=>833,'\''=>278,'('=>333,')'=>333,'*'=>500,'+'=>570, + ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>570,'='=>570,'>'=>570,'?'=>500,'@'=>930,'A'=>722, + 'B'=>667,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>778,'I'=>389,'J'=>500,'K'=>778,'L'=>667,'M'=>944,'N'=>722,'O'=>778,'P'=>611,'Q'=>778,'R'=>722,'S'=>556,'T'=>667,'U'=>722,'V'=>722,'W'=>1000, + 'X'=>722,'Y'=>722,'Z'=>667,'['=>333,'\\'=>278,']'=>333,'^'=>581,'_'=>500,'`'=>333,'a'=>500,'b'=>556,'c'=>444,'d'=>556,'e'=>444,'f'=>333,'g'=>500,'h'=>556,'i'=>278,'j'=>333,'k'=>556,'l'=>278,'m'=>833, + 'n'=>556,'o'=>500,'p'=>556,'q'=>556,'r'=>444,'s'=>389,'t'=>333,'u'=>556,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>444,'{'=>394,'|'=>220,'}'=>394,'~'=>520,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500, + chr(132)=>500,chr(133)=>1000,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>556,chr(139)=>333,chr(140)=>1000,chr(141)=>350,chr(142)=>667,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>500,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>389,chr(155)=>333,chr(156)=>722,chr(157)=>350,chr(158)=>444,chr(159)=>722,chr(160)=>250,chr(161)=>333,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>220,chr(167)=>500,chr(168)=>333,chr(169)=>747,chr(170)=>300,chr(171)=>500,chr(172)=>570,chr(173)=>333,chr(174)=>747,chr(175)=>333, + chr(176)=>400,chr(177)=>570,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>556,chr(182)=>540,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>330,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>500,chr(192)=>722,chr(193)=>722,chr(194)=>722,chr(195)=>722,chr(196)=>722,chr(197)=>722, + chr(198)=>1000,chr(199)=>722,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>389,chr(205)=>389,chr(206)=>389,chr(207)=>389,chr(208)=>722,chr(209)=>722,chr(210)=>778,chr(211)=>778,chr(212)=>778,chr(213)=>778,chr(214)=>778,chr(215)=>570,chr(216)=>778,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>722,chr(222)=>611,chr(223)=>556,chr(224)=>500,chr(225)=>500,chr(226)=>500,chr(227)=>500,chr(228)=>500,chr(229)=>500,chr(230)=>722,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>556, + chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>570,chr(248)=>500,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>500,chr(254)=>556,chr(255)=>500); $enc = 'cp1252'; -$uv = [0 => [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/timesbi.php b/app/ThirdParty/fpdf/font/timesbi.php index 2edef0e7..089f21ab 100644 --- a/app/ThirdParty/fpdf/font/timesbi.php +++ b/app/ThirdParty/fpdf/font/timesbi.php @@ -1,21 +1,21 @@ 250, chr(1) => 250, chr(2) => 250, chr(3) => 250, chr(4) => 250, chr(5) => 250, chr(6) => 250, chr(7) => 250, chr(8) => 250, chr(9) => 250, chr(10) => 250, chr(11) => 250, chr(12) => 250, chr(13) => 250, chr(14) => 250, chr(15) => 250, chr(16) => 250, chr(17) => 250, chr(18) => 250, chr(19) => 250, chr(20) => 250, chr(21) => 250, - chr(22) => 250, chr(23) => 250, chr(24) => 250, chr(25) => 250, chr(26) => 250, chr(27) => 250, chr(28) => 250, chr(29) => 250, chr(30) => 250, chr(31) => 250, ' ' => 250, '!' => 389, '"' => 555, '#' => 500, '$' => 500, '%' => 833, '&' => 778, '\'' => 278, '(' => 333, ')' => 333, '*' => 500, '+' => 570, - ',' => 250, '-' => 333, '.' => 250, '/' => 278, '0' => 500, '1' => 500, '2' => 500, '3' => 500, '4' => 500, '5' => 500, '6' => 500, '7' => 500, '8' => 500, '9' => 500, ':' => 333, ';' => 333, '<' => 570, '=' => 570, '>' => 570, '?' => 500, '@' => 832, 'A' => 667, - 'B' => 667, 'C' => 667, 'D' => 722, 'E' => 667, 'F' => 667, 'G' => 722, 'H' => 778, 'I' => 389, 'J' => 500, 'K' => 667, 'L' => 611, 'M' => 889, 'N' => 722, 'O' => 722, 'P' => 611, 'Q' => 722, 'R' => 667, 'S' => 556, 'T' => 611, 'U' => 722, 'V' => 667, 'W' => 889, - 'X' => 667, 'Y' => 611, 'Z' => 611, '[' => 333, '\\' => 278, ']' => 333, '^' => 570, '_' => 500, '`' => 333, 'a' => 500, 'b' => 500, 'c' => 444, 'd' => 500, 'e' => 444, 'f' => 333, 'g' => 500, 'h' => 556, 'i' => 278, 'j' => 278, 'k' => 500, 'l' => 278, 'm' => 778, - 'n' => 556, 'o' => 500, 'p' => 500, 'q' => 500, 'r' => 389, 's' => 389, 't' => 278, 'u' => 556, 'v' => 444, 'w' => 667, 'x' => 500, 'y' => 444, 'z' => 389, '{' => 348, '|' => 220, '}' => 348, '~' => 570, chr(127) => 350, chr(128) => 500, chr(129) => 350, chr(130) => 333, chr(131) => 500, - chr(132) => 500, chr(133) => 1000, chr(134) => 500, chr(135) => 500, chr(136) => 333, chr(137) => 1000, chr(138) => 556, chr(139) => 333, chr(140) => 944, chr(141) => 350, chr(142) => 611, chr(143) => 350, chr(144) => 350, chr(145) => 333, chr(146) => 333, chr(147) => 500, chr(148) => 500, chr(149) => 350, chr(150) => 500, chr(151) => 1000, chr(152) => 333, chr(153) => 1000, - chr(154) => 389, chr(155) => 333, chr(156) => 722, chr(157) => 350, chr(158) => 389, chr(159) => 611, chr(160) => 250, chr(161) => 389, chr(162) => 500, chr(163) => 500, chr(164) => 500, chr(165) => 500, chr(166) => 220, chr(167) => 500, chr(168) => 333, chr(169) => 747, chr(170) => 266, chr(171) => 500, chr(172) => 606, chr(173) => 333, chr(174) => 747, chr(175) => 333, - chr(176) => 400, chr(177) => 570, chr(178) => 300, chr(179) => 300, chr(180) => 333, chr(181) => 576, chr(182) => 500, chr(183) => 250, chr(184) => 333, chr(185) => 300, chr(186) => 300, chr(187) => 500, chr(188) => 750, chr(189) => 750, chr(190) => 750, chr(191) => 500, chr(192) => 667, chr(193) => 667, chr(194) => 667, chr(195) => 667, chr(196) => 667, chr(197) => 667, - chr(198) => 944, chr(199) => 667, chr(200) => 667, chr(201) => 667, chr(202) => 667, chr(203) => 667, chr(204) => 389, chr(205) => 389, chr(206) => 389, chr(207) => 389, chr(208) => 722, chr(209) => 722, chr(210) => 722, chr(211) => 722, chr(212) => 722, chr(213) => 722, chr(214) => 722, chr(215) => 570, chr(216) => 722, chr(217) => 722, chr(218) => 722, chr(219) => 722, - chr(220) => 722, chr(221) => 611, chr(222) => 611, chr(223) => 500, chr(224) => 500, chr(225) => 500, chr(226) => 500, chr(227) => 500, chr(228) => 500, chr(229) => 500, chr(230) => 722, chr(231) => 444, chr(232) => 444, chr(233) => 444, chr(234) => 444, chr(235) => 444, chr(236) => 278, chr(237) => 278, chr(238) => 278, chr(239) => 278, chr(240) => 500, chr(241) => 556, - chr(242) => 500, chr(243) => 500, chr(244) => 500, chr(245) => 500, chr(246) => 500, chr(247) => 570, chr(248) => 500, chr(249) => 556, chr(250) => 556, chr(251) => 556, chr(252) => 556, chr(253) => 444, chr(254) => 500, chr(255) => 444]; +$cw = array( + chr(0)=>250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250, + chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>389,'"'=>555,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>278,'('=>333,')'=>333,'*'=>500,'+'=>570, + ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>570,'='=>570,'>'=>570,'?'=>500,'@'=>832,'A'=>667, + 'B'=>667,'C'=>667,'D'=>722,'E'=>667,'F'=>667,'G'=>722,'H'=>778,'I'=>389,'J'=>500,'K'=>667,'L'=>611,'M'=>889,'N'=>722,'O'=>722,'P'=>611,'Q'=>722,'R'=>667,'S'=>556,'T'=>611,'U'=>722,'V'=>667,'W'=>889, + 'X'=>667,'Y'=>611,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>570,'_'=>500,'`'=>333,'a'=>500,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>333,'g'=>500,'h'=>556,'i'=>278,'j'=>278,'k'=>500,'l'=>278,'m'=>778, + 'n'=>556,'o'=>500,'p'=>500,'q'=>500,'r'=>389,'s'=>389,'t'=>278,'u'=>556,'v'=>444,'w'=>667,'x'=>500,'y'=>444,'z'=>389,'{'=>348,'|'=>220,'}'=>348,'~'=>570,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500, + chr(132)=>500,chr(133)=>1000,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>556,chr(139)=>333,chr(140)=>944,chr(141)=>350,chr(142)=>611,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>500,chr(148)=>500,chr(149)=>350,chr(150)=>500,chr(151)=>1000,chr(152)=>333,chr(153)=>1000, + chr(154)=>389,chr(155)=>333,chr(156)=>722,chr(157)=>350,chr(158)=>389,chr(159)=>611,chr(160)=>250,chr(161)=>389,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>220,chr(167)=>500,chr(168)=>333,chr(169)=>747,chr(170)=>266,chr(171)=>500,chr(172)=>606,chr(173)=>333,chr(174)=>747,chr(175)=>333, + chr(176)=>400,chr(177)=>570,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>576,chr(182)=>500,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>300,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>500,chr(192)=>667,chr(193)=>667,chr(194)=>667,chr(195)=>667,chr(196)=>667,chr(197)=>667, + chr(198)=>944,chr(199)=>667,chr(200)=>667,chr(201)=>667,chr(202)=>667,chr(203)=>667,chr(204)=>389,chr(205)=>389,chr(206)=>389,chr(207)=>389,chr(208)=>722,chr(209)=>722,chr(210)=>722,chr(211)=>722,chr(212)=>722,chr(213)=>722,chr(214)=>722,chr(215)=>570,chr(216)=>722,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>611,chr(222)=>611,chr(223)=>500,chr(224)=>500,chr(225)=>500,chr(226)=>500,chr(227)=>500,chr(228)=>500,chr(229)=>500,chr(230)=>722,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>556, + chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>570,chr(248)=>500,chr(249)=>556,chr(250)=>556,chr(251)=>556,chr(252)=>556,chr(253)=>444,chr(254)=>500,chr(255)=>444); $enc = 'cp1252'; -$uv = [0 => [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/timesi.php b/app/ThirdParty/fpdf/font/timesi.php index e26de456..f958b5b6 100644 --- a/app/ThirdParty/fpdf/font/timesi.php +++ b/app/ThirdParty/fpdf/font/timesi.php @@ -1,21 +1,21 @@ 250, chr(1) => 250, chr(2) => 250, chr(3) => 250, chr(4) => 250, chr(5) => 250, chr(6) => 250, chr(7) => 250, chr(8) => 250, chr(9) => 250, chr(10) => 250, chr(11) => 250, chr(12) => 250, chr(13) => 250, chr(14) => 250, chr(15) => 250, chr(16) => 250, chr(17) => 250, chr(18) => 250, chr(19) => 250, chr(20) => 250, chr(21) => 250, - chr(22) => 250, chr(23) => 250, chr(24) => 250, chr(25) => 250, chr(26) => 250, chr(27) => 250, chr(28) => 250, chr(29) => 250, chr(30) => 250, chr(31) => 250, ' ' => 250, '!' => 333, '"' => 420, '#' => 500, '$' => 500, '%' => 833, '&' => 778, '\'' => 214, '(' => 333, ')' => 333, '*' => 500, '+' => 675, - ',' => 250, '-' => 333, '.' => 250, '/' => 278, '0' => 500, '1' => 500, '2' => 500, '3' => 500, '4' => 500, '5' => 500, '6' => 500, '7' => 500, '8' => 500, '9' => 500, ':' => 333, ';' => 333, '<' => 675, '=' => 675, '>' => 675, '?' => 500, '@' => 920, 'A' => 611, - 'B' => 611, 'C' => 667, 'D' => 722, 'E' => 611, 'F' => 611, 'G' => 722, 'H' => 722, 'I' => 333, 'J' => 444, 'K' => 667, 'L' => 556, 'M' => 833, 'N' => 667, 'O' => 722, 'P' => 611, 'Q' => 722, 'R' => 611, 'S' => 500, 'T' => 556, 'U' => 722, 'V' => 611, 'W' => 833, - 'X' => 611, 'Y' => 556, 'Z' => 556, '[' => 389, '\\' => 278, ']' => 389, '^' => 422, '_' => 500, '`' => 333, 'a' => 500, 'b' => 500, 'c' => 444, 'd' => 500, 'e' => 444, 'f' => 278, 'g' => 500, 'h' => 500, 'i' => 278, 'j' => 278, 'k' => 444, 'l' => 278, 'm' => 722, - 'n' => 500, 'o' => 500, 'p' => 500, 'q' => 500, 'r' => 389, 's' => 389, 't' => 278, 'u' => 500, 'v' => 444, 'w' => 667, 'x' => 444, 'y' => 444, 'z' => 389, '{' => 400, '|' => 275, '}' => 400, '~' => 541, chr(127) => 350, chr(128) => 500, chr(129) => 350, chr(130) => 333, chr(131) => 500, - chr(132) => 556, chr(133) => 889, chr(134) => 500, chr(135) => 500, chr(136) => 333, chr(137) => 1000, chr(138) => 500, chr(139) => 333, chr(140) => 944, chr(141) => 350, chr(142) => 556, chr(143) => 350, chr(144) => 350, chr(145) => 333, chr(146) => 333, chr(147) => 556, chr(148) => 556, chr(149) => 350, chr(150) => 500, chr(151) => 889, chr(152) => 333, chr(153) => 980, - chr(154) => 389, chr(155) => 333, chr(156) => 667, chr(157) => 350, chr(158) => 389, chr(159) => 556, chr(160) => 250, chr(161) => 389, chr(162) => 500, chr(163) => 500, chr(164) => 500, chr(165) => 500, chr(166) => 275, chr(167) => 500, chr(168) => 333, chr(169) => 760, chr(170) => 276, chr(171) => 500, chr(172) => 675, chr(173) => 333, chr(174) => 760, chr(175) => 333, - chr(176) => 400, chr(177) => 675, chr(178) => 300, chr(179) => 300, chr(180) => 333, chr(181) => 500, chr(182) => 523, chr(183) => 250, chr(184) => 333, chr(185) => 300, chr(186) => 310, chr(187) => 500, chr(188) => 750, chr(189) => 750, chr(190) => 750, chr(191) => 500, chr(192) => 611, chr(193) => 611, chr(194) => 611, chr(195) => 611, chr(196) => 611, chr(197) => 611, - chr(198) => 889, chr(199) => 667, chr(200) => 611, chr(201) => 611, chr(202) => 611, chr(203) => 611, chr(204) => 333, chr(205) => 333, chr(206) => 333, chr(207) => 333, chr(208) => 722, chr(209) => 667, chr(210) => 722, chr(211) => 722, chr(212) => 722, chr(213) => 722, chr(214) => 722, chr(215) => 675, chr(216) => 722, chr(217) => 722, chr(218) => 722, chr(219) => 722, - chr(220) => 722, chr(221) => 556, chr(222) => 611, chr(223) => 500, chr(224) => 500, chr(225) => 500, chr(226) => 500, chr(227) => 500, chr(228) => 500, chr(229) => 500, chr(230) => 667, chr(231) => 444, chr(232) => 444, chr(233) => 444, chr(234) => 444, chr(235) => 444, chr(236) => 278, chr(237) => 278, chr(238) => 278, chr(239) => 278, chr(240) => 500, chr(241) => 500, - chr(242) => 500, chr(243) => 500, chr(244) => 500, chr(245) => 500, chr(246) => 500, chr(247) => 675, chr(248) => 500, chr(249) => 500, chr(250) => 500, chr(251) => 500, chr(252) => 500, chr(253) => 444, chr(254) => 500, chr(255) => 444]; +$cw = array( + chr(0)=>250,chr(1)=>250,chr(2)=>250,chr(3)=>250,chr(4)=>250,chr(5)=>250,chr(6)=>250,chr(7)=>250,chr(8)=>250,chr(9)=>250,chr(10)=>250,chr(11)=>250,chr(12)=>250,chr(13)=>250,chr(14)=>250,chr(15)=>250,chr(16)=>250,chr(17)=>250,chr(18)=>250,chr(19)=>250,chr(20)=>250,chr(21)=>250, + chr(22)=>250,chr(23)=>250,chr(24)=>250,chr(25)=>250,chr(26)=>250,chr(27)=>250,chr(28)=>250,chr(29)=>250,chr(30)=>250,chr(31)=>250,' '=>250,'!'=>333,'"'=>420,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>214,'('=>333,')'=>333,'*'=>500,'+'=>675, + ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>675,'='=>675,'>'=>675,'?'=>500,'@'=>920,'A'=>611, + 'B'=>611,'C'=>667,'D'=>722,'E'=>611,'F'=>611,'G'=>722,'H'=>722,'I'=>333,'J'=>444,'K'=>667,'L'=>556,'M'=>833,'N'=>667,'O'=>722,'P'=>611,'Q'=>722,'R'=>611,'S'=>500,'T'=>556,'U'=>722,'V'=>611,'W'=>833, + 'X'=>611,'Y'=>556,'Z'=>556,'['=>389,'\\'=>278,']'=>389,'^'=>422,'_'=>500,'`'=>333,'a'=>500,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>278,'g'=>500,'h'=>500,'i'=>278,'j'=>278,'k'=>444,'l'=>278,'m'=>722, + 'n'=>500,'o'=>500,'p'=>500,'q'=>500,'r'=>389,'s'=>389,'t'=>278,'u'=>500,'v'=>444,'w'=>667,'x'=>444,'y'=>444,'z'=>389,'{'=>400,'|'=>275,'}'=>400,'~'=>541,chr(127)=>350,chr(128)=>500,chr(129)=>350,chr(130)=>333,chr(131)=>500, + chr(132)=>556,chr(133)=>889,chr(134)=>500,chr(135)=>500,chr(136)=>333,chr(137)=>1000,chr(138)=>500,chr(139)=>333,chr(140)=>944,chr(141)=>350,chr(142)=>556,chr(143)=>350,chr(144)=>350,chr(145)=>333,chr(146)=>333,chr(147)=>556,chr(148)=>556,chr(149)=>350,chr(150)=>500,chr(151)=>889,chr(152)=>333,chr(153)=>980, + chr(154)=>389,chr(155)=>333,chr(156)=>667,chr(157)=>350,chr(158)=>389,chr(159)=>556,chr(160)=>250,chr(161)=>389,chr(162)=>500,chr(163)=>500,chr(164)=>500,chr(165)=>500,chr(166)=>275,chr(167)=>500,chr(168)=>333,chr(169)=>760,chr(170)=>276,chr(171)=>500,chr(172)=>675,chr(173)=>333,chr(174)=>760,chr(175)=>333, + chr(176)=>400,chr(177)=>675,chr(178)=>300,chr(179)=>300,chr(180)=>333,chr(181)=>500,chr(182)=>523,chr(183)=>250,chr(184)=>333,chr(185)=>300,chr(186)=>310,chr(187)=>500,chr(188)=>750,chr(189)=>750,chr(190)=>750,chr(191)=>500,chr(192)=>611,chr(193)=>611,chr(194)=>611,chr(195)=>611,chr(196)=>611,chr(197)=>611, + chr(198)=>889,chr(199)=>667,chr(200)=>611,chr(201)=>611,chr(202)=>611,chr(203)=>611,chr(204)=>333,chr(205)=>333,chr(206)=>333,chr(207)=>333,chr(208)=>722,chr(209)=>667,chr(210)=>722,chr(211)=>722,chr(212)=>722,chr(213)=>722,chr(214)=>722,chr(215)=>675,chr(216)=>722,chr(217)=>722,chr(218)=>722,chr(219)=>722, + chr(220)=>722,chr(221)=>556,chr(222)=>611,chr(223)=>500,chr(224)=>500,chr(225)=>500,chr(226)=>500,chr(227)=>500,chr(228)=>500,chr(229)=>500,chr(230)=>667,chr(231)=>444,chr(232)=>444,chr(233)=>444,chr(234)=>444,chr(235)=>444,chr(236)=>278,chr(237)=>278,chr(238)=>278,chr(239)=>278,chr(240)=>500,chr(241)=>500, + chr(242)=>500,chr(243)=>500,chr(244)=>500,chr(245)=>500,chr(246)=>500,chr(247)=>675,chr(248)=>500,chr(249)=>500,chr(250)=>500,chr(251)=>500,chr(252)=>500,chr(253)=>444,chr(254)=>500,chr(255)=>444); $enc = 'cp1252'; -$uv = [0 => [0, 128], 128 => 8364, 130 => 8218, 131 => 402, 132 => 8222, 133 => 8230, 134 => [8224, 2], 136 => 710, 137 => 8240, 138 => 352, 139 => 8249, 140 => 338, 142 => 381, 145 => [8216, 2], 147 => [8220, 2], 149 => 8226, 150 => [8211, 2], 152 => 732, 153 => 8482, 154 => 353, 155 => 8250, 156 => 339, 158 => 382, 159 => 376, 160 => [160, 96]]; +$uv = array(0=>array(0,128),128=>8364,130=>8218,131=>402,132=>8222,133=>8230,134=>array(8224,2),136=>710,137=>8240,138=>352,139=>8249,140=>338,142=>381,145=>array(8216,2),147=>array(8220,2),149=>8226,150=>array(8211,2),152=>732,153=>8482,154=>353,155=>8250,156=>339,158=>382,159=>376,160=>array(160,96)); +?> diff --git a/app/ThirdParty/fpdf/font/zapfdingbats.php b/app/ThirdParty/fpdf/font/zapfdingbats.php index d236518f..7c2cb5e4 100644 --- a/app/ThirdParty/fpdf/font/zapfdingbats.php +++ b/app/ThirdParty/fpdf/font/zapfdingbats.php @@ -1,20 +1,20 @@ 0, chr(1) => 0, chr(2) => 0, chr(3) => 0, chr(4) => 0, chr(5) => 0, chr(6) => 0, chr(7) => 0, chr(8) => 0, chr(9) => 0, chr(10) => 0, chr(11) => 0, chr(12) => 0, chr(13) => 0, chr(14) => 0, chr(15) => 0, chr(16) => 0, chr(17) => 0, chr(18) => 0, chr(19) => 0, chr(20) => 0, chr(21) => 0, - chr(22) => 0, chr(23) => 0, chr(24) => 0, chr(25) => 0, chr(26) => 0, chr(27) => 0, chr(28) => 0, chr(29) => 0, chr(30) => 0, chr(31) => 0, ' ' => 278, '!' => 974, '"' => 961, '#' => 974, '$' => 980, '%' => 719, '&' => 789, '\'' => 790, '(' => 791, ')' => 690, '*' => 960, '+' => 939, - ',' => 549, '-' => 855, '.' => 911, '/' => 933, '0' => 911, '1' => 945, '2' => 974, '3' => 755, '4' => 846, '5' => 762, '6' => 761, '7' => 571, '8' => 677, '9' => 763, ':' => 760, ';' => 759, '<' => 754, '=' => 494, '>' => 552, '?' => 537, '@' => 577, 'A' => 692, - 'B' => 786, 'C' => 788, 'D' => 788, 'E' => 790, 'F' => 793, 'G' => 794, 'H' => 816, 'I' => 823, 'J' => 789, 'K' => 841, 'L' => 823, 'M' => 833, 'N' => 816, 'O' => 831, 'P' => 923, 'Q' => 744, 'R' => 723, 'S' => 749, 'T' => 790, 'U' => 792, 'V' => 695, 'W' => 776, - 'X' => 768, 'Y' => 792, 'Z' => 759, '[' => 707, '\\' => 708, ']' => 682, '^' => 701, '_' => 826, '`' => 815, 'a' => 789, 'b' => 789, 'c' => 707, 'd' => 687, 'e' => 696, 'f' => 689, 'g' => 786, 'h' => 787, 'i' => 713, 'j' => 791, 'k' => 785, 'l' => 791, 'm' => 873, - 'n' => 761, 'o' => 762, 'p' => 762, 'q' => 759, 'r' => 759, 's' => 892, 't' => 892, 'u' => 788, 'v' => 784, 'w' => 438, 'x' => 138, 'y' => 277, 'z' => 415, '{' => 392, '|' => 392, '}' => 668, '~' => 668, chr(127) => 0, chr(128) => 390, chr(129) => 390, chr(130) => 317, chr(131) => 317, - chr(132) => 276, chr(133) => 276, chr(134) => 509, chr(135) => 509, chr(136) => 410, chr(137) => 410, chr(138) => 234, chr(139) => 234, chr(140) => 334, chr(141) => 334, chr(142) => 0, chr(143) => 0, chr(144) => 0, chr(145) => 0, chr(146) => 0, chr(147) => 0, chr(148) => 0, chr(149) => 0, chr(150) => 0, chr(151) => 0, chr(152) => 0, chr(153) => 0, - chr(154) => 0, chr(155) => 0, chr(156) => 0, chr(157) => 0, chr(158) => 0, chr(159) => 0, chr(160) => 0, chr(161) => 732, chr(162) => 544, chr(163) => 544, chr(164) => 910, chr(165) => 667, chr(166) => 760, chr(167) => 760, chr(168) => 776, chr(169) => 595, chr(170) => 694, chr(171) => 626, chr(172) => 788, chr(173) => 788, chr(174) => 788, chr(175) => 788, - chr(176) => 788, chr(177) => 788, chr(178) => 788, chr(179) => 788, chr(180) => 788, chr(181) => 788, chr(182) => 788, chr(183) => 788, chr(184) => 788, chr(185) => 788, chr(186) => 788, chr(187) => 788, chr(188) => 788, chr(189) => 788, chr(190) => 788, chr(191) => 788, chr(192) => 788, chr(193) => 788, chr(194) => 788, chr(195) => 788, chr(196) => 788, chr(197) => 788, - chr(198) => 788, chr(199) => 788, chr(200) => 788, chr(201) => 788, chr(202) => 788, chr(203) => 788, chr(204) => 788, chr(205) => 788, chr(206) => 788, chr(207) => 788, chr(208) => 788, chr(209) => 788, chr(210) => 788, chr(211) => 788, chr(212) => 894, chr(213) => 838, chr(214) => 1016, chr(215) => 458, chr(216) => 748, chr(217) => 924, chr(218) => 748, chr(219) => 918, - chr(220) => 927, chr(221) => 928, chr(222) => 928, chr(223) => 834, chr(224) => 873, chr(225) => 828, chr(226) => 924, chr(227) => 924, chr(228) => 917, chr(229) => 930, chr(230) => 931, chr(231) => 463, chr(232) => 883, chr(233) => 836, chr(234) => 836, chr(235) => 867, chr(236) => 867, chr(237) => 696, chr(238) => 696, chr(239) => 874, chr(240) => 0, chr(241) => 874, - chr(242) => 760, chr(243) => 946, chr(244) => 771, chr(245) => 865, chr(246) => 771, chr(247) => 888, chr(248) => 967, chr(249) => 888, chr(250) => 831, chr(251) => 873, chr(252) => 927, chr(253) => 970, chr(254) => 918, chr(255) => 0]; -$uv = [32 => 32, 33 => [9985, 4], 37 => 9742, 38 => [9990, 4], 42 => 9755, 43 => 9758, 44 => [9996, 28], 72 => 9733, 73 => [10025, 35], 108 => 9679, 109 => 10061, 110 => 9632, 111 => [10063, 4], 115 => 9650, 116 => 9660, 117 => 9670, 118 => 10070, 119 => 9687, 120 => [10072, 7], 128 => [10088, 14], 161 => [10081, 7], 168 => 9827, 169 => 9830, 170 => 9829, 171 => 9824, 172 => [9312, 10], 182 => [10102, 31], 213 => 8594, 214 => [8596, 2], 216 => [10136, 24], 241 => [10161, 14]]; +$cw = array( + chr(0)=>0,chr(1)=>0,chr(2)=>0,chr(3)=>0,chr(4)=>0,chr(5)=>0,chr(6)=>0,chr(7)=>0,chr(8)=>0,chr(9)=>0,chr(10)=>0,chr(11)=>0,chr(12)=>0,chr(13)=>0,chr(14)=>0,chr(15)=>0,chr(16)=>0,chr(17)=>0,chr(18)=>0,chr(19)=>0,chr(20)=>0,chr(21)=>0, + chr(22)=>0,chr(23)=>0,chr(24)=>0,chr(25)=>0,chr(26)=>0,chr(27)=>0,chr(28)=>0,chr(29)=>0,chr(30)=>0,chr(31)=>0,' '=>278,'!'=>974,'"'=>961,'#'=>974,'$'=>980,'%'=>719,'&'=>789,'\''=>790,'('=>791,')'=>690,'*'=>960,'+'=>939, + ','=>549,'-'=>855,'.'=>911,'/'=>933,'0'=>911,'1'=>945,'2'=>974,'3'=>755,'4'=>846,'5'=>762,'6'=>761,'7'=>571,'8'=>677,'9'=>763,':'=>760,';'=>759,'<'=>754,'='=>494,'>'=>552,'?'=>537,'@'=>577,'A'=>692, + 'B'=>786,'C'=>788,'D'=>788,'E'=>790,'F'=>793,'G'=>794,'H'=>816,'I'=>823,'J'=>789,'K'=>841,'L'=>823,'M'=>833,'N'=>816,'O'=>831,'P'=>923,'Q'=>744,'R'=>723,'S'=>749,'T'=>790,'U'=>792,'V'=>695,'W'=>776, + 'X'=>768,'Y'=>792,'Z'=>759,'['=>707,'\\'=>708,']'=>682,'^'=>701,'_'=>826,'`'=>815,'a'=>789,'b'=>789,'c'=>707,'d'=>687,'e'=>696,'f'=>689,'g'=>786,'h'=>787,'i'=>713,'j'=>791,'k'=>785,'l'=>791,'m'=>873, + 'n'=>761,'o'=>762,'p'=>762,'q'=>759,'r'=>759,'s'=>892,'t'=>892,'u'=>788,'v'=>784,'w'=>438,'x'=>138,'y'=>277,'z'=>415,'{'=>392,'|'=>392,'}'=>668,'~'=>668,chr(127)=>0,chr(128)=>390,chr(129)=>390,chr(130)=>317,chr(131)=>317, + chr(132)=>276,chr(133)=>276,chr(134)=>509,chr(135)=>509,chr(136)=>410,chr(137)=>410,chr(138)=>234,chr(139)=>234,chr(140)=>334,chr(141)=>334,chr(142)=>0,chr(143)=>0,chr(144)=>0,chr(145)=>0,chr(146)=>0,chr(147)=>0,chr(148)=>0,chr(149)=>0,chr(150)=>0,chr(151)=>0,chr(152)=>0,chr(153)=>0, + chr(154)=>0,chr(155)=>0,chr(156)=>0,chr(157)=>0,chr(158)=>0,chr(159)=>0,chr(160)=>0,chr(161)=>732,chr(162)=>544,chr(163)=>544,chr(164)=>910,chr(165)=>667,chr(166)=>760,chr(167)=>760,chr(168)=>776,chr(169)=>595,chr(170)=>694,chr(171)=>626,chr(172)=>788,chr(173)=>788,chr(174)=>788,chr(175)=>788, + chr(176)=>788,chr(177)=>788,chr(178)=>788,chr(179)=>788,chr(180)=>788,chr(181)=>788,chr(182)=>788,chr(183)=>788,chr(184)=>788,chr(185)=>788,chr(186)=>788,chr(187)=>788,chr(188)=>788,chr(189)=>788,chr(190)=>788,chr(191)=>788,chr(192)=>788,chr(193)=>788,chr(194)=>788,chr(195)=>788,chr(196)=>788,chr(197)=>788, + chr(198)=>788,chr(199)=>788,chr(200)=>788,chr(201)=>788,chr(202)=>788,chr(203)=>788,chr(204)=>788,chr(205)=>788,chr(206)=>788,chr(207)=>788,chr(208)=>788,chr(209)=>788,chr(210)=>788,chr(211)=>788,chr(212)=>894,chr(213)=>838,chr(214)=>1016,chr(215)=>458,chr(216)=>748,chr(217)=>924,chr(218)=>748,chr(219)=>918, + chr(220)=>927,chr(221)=>928,chr(222)=>928,chr(223)=>834,chr(224)=>873,chr(225)=>828,chr(226)=>924,chr(227)=>924,chr(228)=>917,chr(229)=>930,chr(230)=>931,chr(231)=>463,chr(232)=>883,chr(233)=>836,chr(234)=>836,chr(235)=>867,chr(236)=>867,chr(237)=>696,chr(238)=>696,chr(239)=>874,chr(240)=>0,chr(241)=>874, + chr(242)=>760,chr(243)=>946,chr(244)=>771,chr(245)=>865,chr(246)=>771,chr(247)=>888,chr(248)=>967,chr(249)=>888,chr(250)=>831,chr(251)=>873,chr(252)=>927,chr(253)=>970,chr(254)=>918,chr(255)=>0); +$uv = array(32=>32,33=>array(9985,4),37=>9742,38=>array(9990,4),42=>9755,43=>9758,44=>array(9996,28),72=>9733,73=>array(10025,35),108=>9679,109=>10061,110=>9632,111=>array(10063,4),115=>9650,116=>9660,117=>9670,118=>10070,119=>9687,120=>array(10072,7),128=>array(10088,14),161=>array(10081,7),168=>9827,169=>9830,170=>9829,171=>9824,172=>array(9312,10),182=>array(10102,31),213=>8594,214=>array(8596,2),216=>array(10136,24),241=>array(10161,14)); +?> diff --git a/app/ThirdParty/fpdf/fpdf.php b/app/ThirdParty/fpdf/fpdf.php index cefd575c..3c76bd5c 100644 --- a/app/ThirdParty/fpdf/fpdf.php +++ b/app/ThirdParty/fpdf/fpdf.php @@ -10,2065 +10,1810 @@ class FPDF { - const VERSION = '1.86'; - - protected $page; // current page number - - protected $n; // current object number - - protected $offsets; // array of object offsets - - protected $buffer; // buffer holding in-memory PDF - - protected $pages; // array containing pages - - protected $state; // current document state - - protected $compress; // compression flag - - protected $iconv; // whether iconv is available - - protected $k; // scale factor (number of points in user unit) - - protected $DefOrientation; // default orientation - - protected $CurOrientation; // current orientation - - protected $StdPageSizes; // standard page sizes - - protected $DefPageSize; // default page size - - protected $CurPageSize; // current page size - - protected $CurRotation; // current page rotation - - protected $PageInfo; // page-related data - - protected $wPt; - - protected $hPt; // dimensions of current page in points - - protected $w; - - protected $h; // dimensions of current page in user unit - - protected $lMargin; // left margin - - protected $tMargin; // top margin - - protected $rMargin; // right margin - - protected $bMargin; // page break margin - - protected $cMargin; // cell margin - - protected $x; - - protected $y; // current position in user unit - - protected $lasth; // height of last printed cell - - protected $LineWidth; // line width in user unit - - protected $fontpath; // directory containing fonts - - protected $CoreFonts; // array of core font names - - protected $fonts; // array of used fonts - - protected $FontFiles; // array of font files - - protected $encodings; // array of encodings - - protected $cmaps; // array of ToUnicode CMaps - - protected $FontFamily; // current font family - - protected $FontStyle; // current font style - - protected $underline; // underlining flag - - protected $CurrentFont; // current font info - - protected $FontSizePt; // current font size in points - - protected $FontSize; // current font size in user unit - - protected $DrawColor; // commands for drawing color - - protected $FillColor; // commands for filling color - - protected $TextColor; // commands for text color - - protected $ColorFlag; // indicates whether fill and text colors are different - - protected $WithAlpha; // indicates whether alpha channel is used - - protected $ws; // word spacing - - protected $images; // array of used images - - protected $PageLinks; // array of links in pages - - protected $links; // array of internal links - - protected $AutoPageBreak; // automatic page breaking - - protected $PageBreakTrigger; // threshold used to trigger page breaks - - protected $InHeader; // flag set when processing header - - protected $InFooter; // flag set when processing footer - - protected $AliasNbPages; // alias for total number of pages - - protected $ZoomMode; // zoom display mode - - protected $LayoutMode; // layout display mode - - protected $metadata; // document properties - - protected $CreationDate; // document creation date - - protected $PDFVersion; // PDF version number - - /******************************************************************************* - * Public methods * - *******************************************************************************/ - - public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4') - { - // FIXED: Set font path directly - $this->fontpath = __DIR__.'/font/'; - - // Initialization of properties - $this->state = 0; - $this->page = 0; - $this->n = 2; - $this->buffer = ''; - $this->pages = []; - $this->PageInfo = []; - $this->fonts = []; - $this->FontFiles = []; - $this->encodings = []; - $this->cmaps = []; - $this->images = []; - $this->links = []; - $this->InHeader = false; - $this->InFooter = false; - $this->lasth = 0; - $this->FontFamily = ''; - $this->FontStyle = ''; - $this->FontSizePt = 12; - $this->underline = false; - $this->DrawColor = '0 G'; - $this->FillColor = '0 g'; - $this->TextColor = '0 g'; - $this->ColorFlag = false; - $this->WithAlpha = false; - $this->ws = 0; - $this->iconv = function_exists('iconv'); - - // Core fonts - $this->CoreFonts = ['courier', 'helvetica', 'times', 'symbol', 'zapfdingbats']; - - // Scale factor - if ($unit == 'pt') { - $this->k = 1; - } elseif ($unit == 'mm') { - $this->k = 72 / 25.4; - } elseif ($unit == 'cm') { - $this->k = 72 / 2.54; - } elseif ($unit == 'in') { - $this->k = 72; - } else { - $this->Error('Incorrect unit: '.$unit); - } - - // Page sizes - $this->StdPageSizes = [ - 'a3' => [841.89, 1190.55], - 'a4' => [595.28, 841.89], - 'a5' => [420.94, 595.28], - 'letter' => [612, 792], - 'legal' => [612, 1008], - ]; - $size = $this->_getpagesize($size); - $this->DefPageSize = $size; - $this->CurPageSize = $size; - - // Page orientation - $orientation = strtolower($orientation); - if ($orientation == 'p' || $orientation == 'portrait') { - $this->DefOrientation = 'P'; - $this->w = $size[0]; - $this->h = $size[1]; - } elseif ($orientation == 'l' || $orientation == 'landscape') { - $this->DefOrientation = 'L'; - $this->w = $size[1]; - $this->h = $size[0]; - } else { - $this->Error('Incorrect orientation: '.$orientation); - } - $this->CurOrientation = $this->DefOrientation; - $this->wPt = $this->w * $this->k; - $this->hPt = $this->h * $this->k; - - // Page rotation - $this->CurRotation = 0; - - // Margins - $margin = 28.35 / $this->k; - $this->SetMargins($margin, $margin); - $this->cMargin = $margin / 10; - $this->LineWidth = .567 / $this->k; - - // Page break - $this->SetAutoPageBreak(true, 2 * $margin); - - // Display and compression - $this->SetDisplayMode('default'); - $this->SetCompression(true); - - // Metadata - $this->metadata = ['Producer' => 'FPDF '.self::VERSION]; - $this->PDFVersion = '1.3'; - } - - public function SetMargins($left, $top, $right = null) - { - // Set left, top and right margins - $this->lMargin = $left; - $this->tMargin = $top; - if ($right === null) { - $right = $left; - } - $this->rMargin = $right; - } - - public function SetLeftMargin($margin) - { - // Set left margin - $this->lMargin = $margin; - if ($this->page > 0 && $this->x < $margin) { - $this->x = $margin; - } - } - - public function SetTopMargin($margin) - { - // Set top margin - $this->tMargin = $margin; - } - - public function SetRightMargin($margin) - { - // Set right margin - $this->rMargin = $margin; - } - - public function SetAutoPageBreak($auto, $margin = 0) - { - // Set auto page break mode and triggering margin - $this->AutoPageBreak = $auto; - $this->bMargin = $margin; - $this->PageBreakTrigger = $this->h - $margin; - } - - public function SetDisplayMode($zoom, $layout = 'default') - { - // Set display mode in viewer - if ($zoom == 'fullpage' || $zoom == 'fullwidth' || $zoom == 'real' || $zoom == 'default' || ! is_string($zoom)) { - $this->ZoomMode = $zoom; - } else { - $this->Error('Incorrect zoom display mode: '.$zoom); - } - if ($layout == 'single' || $layout == 'continuous' || $layout == 'two' || $layout == 'default') { - $this->LayoutMode = $layout; - } else { - $this->Error('Incorrect layout display mode: '.$layout); - } - } - - public function SetCompression($compress) - { - // Set page compression - if (function_exists('gzcompress')) { - $this->compress = $compress; - } else { - $this->compress = false; - } - } - - public function SetTitle($title, $isUTF8 = false) - { - // Title of document - $this->metadata['Title'] = $isUTF8 ? $title : $this->_UTF8encode($title); - } - - public function SetAuthor($author, $isUTF8 = false) - { - // Author of document - $this->metadata['Author'] = $isUTF8 ? $author : $this->_UTF8encode($author); - } - - public function SetSubject($subject, $isUTF8 = false) - { - // Subject of document - $this->metadata['Subject'] = $isUTF8 ? $subject : $this->_UTF8encode($subject); - } - - public function SetKeywords($keywords, $isUTF8 = false) - { - // Keywords of document - $this->metadata['Keywords'] = $isUTF8 ? $keywords : $this->_UTF8encode($keywords); - } - - public function SetCreator($creator, $isUTF8 = false) - { - // Creator of document - $this->metadata['Creator'] = $isUTF8 ? $creator : $this->_UTF8encode($creator); - } - - public function AliasNbPages($alias = '{nb}') - { - // Define an alias for total number of pages - $this->AliasNbPages = $alias; - } - - public function Error($msg) - { - // Fatal error - throw new Exception('FPDF error: '.$msg); - } - - public function Close() - { - // Terminate document - if ($this->state == 3) { - return; - } - if ($this->page == 0) { - $this->AddPage(); - } - // Page footer - $this->InFooter = true; - $this->Footer(); - $this->InFooter = false; - // Close page - $this->_endpage(); - // Close document - $this->_enddoc(); - } - - public function AddPage($orientation = '', $size = '', $rotation = 0) - { - // Start a new page - if ($this->state == 3) { - $this->Error('The document is closed'); - } - $family = $this->FontFamily; - $style = $this->FontStyle.($this->underline ? 'U' : ''); - $fontsize = $this->FontSizePt; - $lw = $this->LineWidth; - $dc = $this->DrawColor; - $fc = $this->FillColor; - $tc = $this->TextColor; - $cf = $this->ColorFlag; - if ($this->page > 0) { - // Page footer - $this->InFooter = true; - $this->Footer(); - $this->InFooter = false; - // Close page - $this->_endpage(); - } - // Start new page - $this->_beginpage($orientation, $size, $rotation); - // Set line cap style to square - $this->_out('2 J'); - // Set line width - $this->LineWidth = $lw; - $this->_out(sprintf('%.2F w', $lw * $this->k)); - // Set font - if ($family) { - $this->SetFont($family, $style, $fontsize); - } - // Set colors - $this->DrawColor = $dc; - if ($dc != '0 G') { - $this->_out($dc); - } - $this->FillColor = $fc; - if ($fc != '0 g') { - $this->_out($fc); - } - $this->TextColor = $tc; - $this->ColorFlag = $cf; - // Page header - $this->InHeader = true; - $this->Header(); - $this->InHeader = false; - // Restore line width - if ($this->LineWidth != $lw) { - $this->LineWidth = $lw; - $this->_out(sprintf('%.2F w', $lw * $this->k)); - } - // Restore font - if ($family) { - $this->SetFont($family, $style, $fontsize); - } - // Restore colors - if ($this->DrawColor != $dc) { - $this->DrawColor = $dc; - $this->_out($dc); - } - if ($this->FillColor != $fc) { - $this->FillColor = $fc; - $this->_out($fc); - } - $this->TextColor = $tc; - $this->ColorFlag = $cf; - } - - public function Header() - { - // To be implemented in your own inherited class - } - - public function Footer() - { - // To be implemented in your own inherited class - } - - public function PageNo() - { - // Get current page number - return $this->page; - } - - public function SetDrawColor($r, $g = null, $b = null) - { - // Set color for all stroking operations - if (($r == 0 && $g == 0 && $b == 0) || $g === null) { - $this->DrawColor = sprintf('%.3F G', $r / 255); - } else { - $this->DrawColor = sprintf('%.3F %.3F %.3F RG', $r / 255, $g / 255, $b / 255); - } - if ($this->page > 0) { - $this->_out($this->DrawColor); - } - } - - public function SetFillColor($r, $g = null, $b = null) - { - // Set color for all filling operations - if (($r == 0 && $g == 0 && $b == 0) || $g === null) { - $this->FillColor = sprintf('%.3F g', $r / 255); - } else { - $this->FillColor = sprintf('%.3F %.3F %.3F rg', $r / 255, $g / 255, $b / 255); - } - $this->ColorFlag = ($this->FillColor != $this->TextColor); - if ($this->page > 0) { - $this->_out($this->FillColor); - } - } - - public function SetTextColor($r, $g = null, $b = null) - { - // Set color for text - if (($r == 0 && $g == 0 && $b == 0) || $g === null) { - $this->TextColor = sprintf('%.3F g', $r / 255); - } else { - $this->TextColor = sprintf('%.3F %.3F %.3F rg', $r / 255, $g / 255, $b / 255); - } - $this->ColorFlag = ($this->FillColor != $this->TextColor); - } - - public function GetStringWidth($s) - { - // Get width of a string in the current font - $cw = $this->CurrentFont['cw']; - $w = 0; - $s = (string) $s; - $l = strlen($s); - for ($i = 0; $i < $l; $i++) { - $w += $cw[$s[$i]]; - } - - return $w * $this->FontSize / 1000; - } - - public function SetLineWidth($width) - { - // Set line width - $this->LineWidth = $width; - if ($this->page > 0) { - $this->_out(sprintf('%.2F w', $width * $this->k)); - } - } - - public function Line($x1, $y1, $x2, $y2) - { - // Draw a line - $this->_out(sprintf('%.2F %.2F m %.2F %.2F l S', $x1 * $this->k, ($this->h - $y1) * $this->k, $x2 * $this->k, ($this->h - $y2) * $this->k)); - } - - public function Rect($x, $y, $w, $h, $style = '') - { - // Draw a rectangle - if ($style == 'F') { - $op = 'f'; - } elseif ($style == 'FD' || $style == 'DF') { - $op = 'B'; - } else { - $op = 'S'; - } - $this->_out(sprintf('%.2F %.2F %.2F %.2F re %s', $x * $this->k, ($this->h - $y) * $this->k, $w * $this->k, -$h * $this->k, $op)); - } - - public function AddFont($family, $style = '', $file = '', $dir = '') - { - // Add a TrueType, OpenType or Type1 font - $family = strtolower($family); - if ($file == '') { - $file = str_replace(' ', '', $family).strtolower($style).'.php'; - } - $style = strtoupper($style); - if ($style == 'IB') { - $style = 'BI'; - } - $fontkey = $family.$style; - if (isset($this->fonts[$fontkey])) { - return; - } - if (strpos($file, '/') !== false || strpos($file, '\\') !== false) { - $this->Error('Incorrect font definition file name: '.$file); - } - if ($dir == '') { - $dir = $this->fontpath; - } - if (substr($dir, -1) != '/' && substr($dir, -1) != '\\') { - $dir .= '/'; - } - $info = $this->_loadfont($dir.$file); - $info['i'] = count($this->fonts) + 1; - if (! empty($info['file'])) { - // Embedded font - $info['file'] = $dir.$info['file']; - if ($info['type'] == 'TrueType') { - $this->FontFiles[$info['file']] = ['length1' => $info['originalsize']]; - } else { - $this->FontFiles[$info['file']] = ['length1' => $info['size1'], 'length2' => $info['size2']]; - } - } - $this->fonts[$fontkey] = $info; - } - - public function SetFont($family, $style = '', $size = 0) - { - // Select a font; size given in points - if ($family == '') { - $family = $this->FontFamily; - } else { - $family = strtolower($family); - } - $style = strtoupper($style); - if (strpos($style, 'U') !== false) { - $this->underline = true; - $style = str_replace('U', '', $style); - } else { - $this->underline = false; - } - if ($style == 'IB') { - $style = 'BI'; - } - if ($size == 0) { - $size = $this->FontSizePt; - } - // Test if font is already selected - if ($this->FontFamily == $family && $this->FontStyle == $style && $this->FontSizePt == $size) { - return; - } - // Test if font is already loaded - $fontkey = $family.$style; - if (! isset($this->fonts[$fontkey])) { - // Test if one of the core fonts - if ($family == 'arial') { - $family = 'helvetica'; - } - if (in_array($family, $this->CoreFonts)) { - if ($family == 'symbol' || $family == 'zapfdingbats') { - $style = ''; - } - $fontkey = $family.$style; - if (! isset($this->fonts[$fontkey])) { - $this->AddFont($family, $style); - } - } else { - $this->Error('Undefined font: '.$family.' '.$style); - } - } - // Select it - $this->FontFamily = $family; - $this->FontStyle = $style; - $this->FontSizePt = $size; - $this->FontSize = $size / $this->k; - $this->CurrentFont = $this->fonts[$fontkey]; - if ($this->page > 0) { - $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); - } - } - - public function SetFontSize($size) - { - // Set font size in points - if ($this->FontSizePt == $size) { - return; - } - $this->FontSizePt = $size; - $this->FontSize = $size / $this->k; - if ($this->page > 0 && isset($this->CurrentFont)) { - $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); - } - } - - public function AddLink() - { - // Create a new internal link - $n = count($this->links) + 1; - $this->links[$n] = [0, 0]; - - return $n; - } - - public function SetLink($link, $y = 0, $page = -1) - { - // Set destination of internal link - if ($y == -1) { - $y = $this->y; - } - if ($page == -1) { - $page = $this->page; - } - $this->links[$link] = [$page, $y]; - } - - public function Link($x, $y, $w, $h, $link) - { - // Put a link on the page - $this->PageLinks[$this->page][] = [$x * $this->k, $this->hPt - $y * $this->k, $w * $this->k, $h * $this->k, $link]; - } - - public function Text($x, $y, $txt) - { - // Output a string - if (! isset($this->CurrentFont)) { - $this->Error('No font has been set'); - } - $txt = (string) $txt; - $s = sprintf('BT %.2F %.2F Td (%s) Tj ET', $x * $this->k, ($this->h - $y) * $this->k, $this->_escape($txt)); - if ($this->underline && $txt !== '') { - $s .= ' '.$this->_dounderline($x, $y, $txt); - } - if ($this->ColorFlag) { - $s = 'q '.$this->TextColor.' '.$s.' Q'; - } - $this->_out($s); - } - - public function AcceptPageBreak() - { - // Accept automatic page break or not - return $this->AutoPageBreak; - } - - public function Cell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = false, $link = '') - { - // Output a cell - $k = $this->k; - if ($this->y + $h > $this->PageBreakTrigger && ! $this->InHeader && ! $this->InFooter && $this->AcceptPageBreak()) { - // Automatic page break - $x = $this->x; - $ws = $this->ws; - if ($ws > 0) { - $this->ws = 0; - $this->_out('0 Tw'); - } - $this->AddPage($this->CurOrientation, $this->CurPageSize, $this->CurRotation); - $this->x = $x; - if ($ws > 0) { - $this->ws = $ws; - $this->_out(sprintf('%.3F Tw', $ws * $k)); - } - } - if ($w == 0) { - $w = $this->w - $this->rMargin - $this->x; - } - $s = ''; - if ($fill || $border == 1) { - if ($fill) { - $op = ($border == 1) ? 'B' : 'f'; - } else { - $op = 'S'; - } - $s = sprintf('%.2F %.2F %.2F %.2F re %s ', $this->x * $k, ($this->h - $this->y) * $k, $w * $k, -$h * $k, $op); - } - if (is_string($border)) { - $x = $this->x; - $y = $this->y; - if (strpos($border, 'L') !== false) { - $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x * $k, ($this->h - $y) * $k, $x * $k, ($this->h - ($y + $h)) * $k); - } - if (strpos($border, 'T') !== false) { - $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - $y) * $k); - } - if (strpos($border, 'R') !== false) { - $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', ($x + $w) * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k); - } - if (strpos($border, 'B') !== false) { - $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x * $k, ($this->h - ($y + $h)) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k); - } - } - $txt = (string) $txt; - if ($txt !== '') { - if (! isset($this->CurrentFont)) { - $this->Error('No font has been set'); - } - if ($align == 'R') { - $dx = $w - $this->cMargin - $this->GetStringWidth($txt); - } elseif ($align == 'C') { - $dx = ($w - $this->GetStringWidth($txt)) / 2; - } else { - $dx = $this->cMargin; - } - if ($this->ColorFlag) { - $s .= 'q '.$this->TextColor.' '; - } - $s .= sprintf('BT %.2F %.2F Td (%s) Tj ET', ($this->x + $dx) * $k, ($this->h - ($this->y + .5 * $h + .3 * $this->FontSize)) * $k, $this->_escape($txt)); - if ($this->underline) { - $s .= ' '.$this->_dounderline($this->x + $dx, $this->y + .5 * $h + .3 * $this->FontSize, $txt); - } - if ($this->ColorFlag) { - $s .= ' Q'; - } - if ($link) { - $this->Link($this->x + $dx, $this->y + .5 * $h - .5 * $this->FontSize, $this->GetStringWidth($txt), $this->FontSize, $link); - } - } - if ($s) { - $this->_out($s); - } - $this->lasth = $h; - if ($ln > 0) { - // Go to next line - $this->y += $h; - if ($ln == 1) { - $this->x = $this->lMargin; - } - } else { - $this->x += $w; - } - } - - public function MultiCell($w, $h, $txt, $border = 0, $align = 'J', $fill = false) - { - // Output text with automatic or explicit line breaks - if (! isset($this->CurrentFont)) { - $this->Error('No font has been set'); - } - $cw = $this->CurrentFont['cw']; - if ($w == 0) { - $w = $this->w - $this->rMargin - $this->x; - } - $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; - $s = str_replace("\r", '', (string) $txt); - $nb = strlen($s); - if ($nb > 0 && $s[$nb - 1] == "\n") { - $nb--; - } - $b = 0; - if ($border) { - if ($border == 1) { - $border = 'LTRB'; - $b = 'LRT'; - $b2 = 'LR'; - } else { - $b2 = ''; - if (strpos($border, 'L') !== false) { - $b2 .= 'L'; - } - if (strpos($border, 'R') !== false) { - $b2 .= 'R'; - } - $b = (strpos($border, 'T') !== false) ? $b2.'T' : $b2; - } - } - $sep = -1; - $i = 0; - $j = 0; - $l = 0; - $ns = 0; - $nl = 1; - while ($i < $nb) { - // Get next character - $c = $s[$i]; - if ($c == "\n") { - // Explicit line break - if ($this->ws > 0) { - $this->ws = 0; - $this->_out('0 Tw'); - } - $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill); - $i++; - $sep = -1; - $j = $i; - $l = 0; - $ns = 0; - $nl++; - if ($border && $nl == 2) { - $b = $b2; - } - - continue; - } - if ($c == ' ') { - $sep = $i; - $ls = $l; - $ns++; - } - $l += $cw[$c]; - if ($l > $wmax) { - // Automatic line break - if ($sep == -1) { - if ($i == $j) { - $i++; - } - if ($this->ws > 0) { - $this->ws = 0; - $this->_out('0 Tw'); - } - $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill); - } else { - if ($align == 'J') { - $this->ws = ($ns > 1) ? ($wmax - $ls) / 1000 * $this->FontSize / ($ns - 1) : 0; - $this->_out(sprintf('%.3F Tw', $this->ws * $this->k)); - } - $this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill); - $i = $sep + 1; - } - $sep = -1; - $j = $i; - $l = 0; - $ns = 0; - $nl++; - if ($border && $nl == 2) { - $b = $b2; - } - } else { - $i++; - } - } - // Last chunk - if ($this->ws > 0) { - $this->ws = 0; - $this->_out('0 Tw'); - } - if ($border && strpos($border, 'B') !== false) { - $b .= 'B'; - } - $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill); - $this->x = $this->lMargin; - } - - public function Write($h, $txt, $link = '') - { - // Output text in flowing mode - if (! isset($this->CurrentFont)) { - $this->Error('No font has been set'); - } - $cw = $this->CurrentFont['cw']; - $w = $this->w - $this->rMargin - $this->x; - $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; - $s = str_replace("\r", '', (string) $txt); - $nb = strlen($s); - $sep = -1; - $i = 0; - $j = 0; - $l = 0; - $nl = 1; - while ($i < $nb) { - // Get next character - $c = $s[$i]; - if ($c == "\n") { - // Explicit line break - $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', false, $link); - $i++; - $sep = -1; - $j = $i; - $l = 0; - if ($nl == 1) { - $this->x = $this->lMargin; - $w = $this->w - $this->rMargin - $this->x; - $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; - } - $nl++; - - continue; - } - if ($c == ' ') { - $sep = $i; - } - $l += $cw[$c]; - if ($l > $wmax) { - // Automatic line break - if ($sep == -1) { - if ($this->x > $this->lMargin) { - // Move to next line - $this->x = $this->lMargin; - $this->y += $h; - $w = $this->w - $this->rMargin - $this->x; - $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; - $i++; - $nl++; - - continue; - } - if ($i == $j) { - $i++; - } - $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', false, $link); - } else { - $this->Cell($w, $h, substr($s, $j, $sep - $j), 0, 2, '', false, $link); - $i = $sep + 1; - } - $sep = -1; - $j = $i; - $l = 0; - if ($nl == 1) { - $this->x = $this->lMargin; - $w = $this->w - $this->rMargin - $this->x; - $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; - } - $nl++; - } else { - $i++; - } - } - // Last chunk - if ($i != $j) { - $this->Cell($l / 1000 * $this->FontSize, $h, substr($s, $j), 0, 0, '', false, $link); - } - } - - public function Ln($h = null) - { - // Line feed; default value is the last cell height - $this->x = $this->lMargin; - if ($h === null) { - $this->y += $this->lasth; - } else { - $this->y += $h; - } - } - - public function Image($file, $x = null, $y = null, $w = 0, $h = 0, $type = '', $link = '') - { - // Put an image on the page - if ($file == '') { - $this->Error('Image file name is empty'); - } - if (! isset($this->images[$file])) { - // First use of this image, get info - if ($type == '') { - $pos = strrpos($file, '.'); - if (! $pos) { - $this->Error('Image file has no extension and no type was specified: '.$file); - } - $type = substr($file, $pos + 1); - } - $type = strtolower($type); - if ($type == 'jpeg') { - $type = 'jpg'; - } - $mtd = '_parse'.$type; - if (! method_exists($this, $mtd)) { - $this->Error('Unsupported image type: '.$type); - } - $info = $this->$mtd($file); - $info['i'] = count($this->images) + 1; - $this->images[$file] = $info; - } else { - $info = $this->images[$file]; - } - - // Automatic width and height calculation if needed - if ($w == 0 && $h == 0) { - // Put image at 96 dpi - $w = -96; - $h = -96; - } - if ($w < 0) { - $w = -$info['w'] * 72 / $w / $this->k; - } - if ($h < 0) { - $h = -$info['h'] * 72 / $h / $this->k; - } - if ($w == 0) { - $w = $h * $info['w'] / $info['h']; - } - if ($h == 0) { - $h = $w * $info['h'] / $info['w']; - } - - // Flowing mode - if ($y === null) { - if ($this->y + $h > $this->PageBreakTrigger && ! $this->InHeader && ! $this->InFooter && $this->AcceptPageBreak()) { - // Automatic page break - $x2 = $this->x; - $this->AddPage($this->CurOrientation, $this->CurPageSize, $this->CurRotation); - $this->x = $x2; - } - $y = $this->y; - $this->y += $h; - } - - if ($x === null) { - $x = $this->x; - } - $this->_out(sprintf('q %.2F 0 0 %.2F %.2F %.2F cm /I%d Do Q', $w * $this->k, $h * $this->k, $x * $this->k, ($this->h - ($y + $h)) * $this->k, $info['i'])); - if ($link) { - $this->Link($x, $y, $w, $h, $link); - } - } - - public function GetPageWidth() - { - // Get current page width - return $this->w; - } - - public function GetPageHeight() - { - // Get current page height - return $this->h; - } - - public function GetX() - { - // Get x position - return $this->x; - } - - public function SetX($x) - { - // Set x position - if ($x >= 0) { - $this->x = $x; - } else { - $this->x = $this->w + $x; - } - } - - public function GetY() - { - // Get y position - return $this->y; - } - - public function SetY($y, $resetX = true) - { - // Set y position and optionally reset x - if ($y >= 0) { - $this->y = $y; - } else { - $this->y = $this->h + $y; - } - if ($resetX) { - $this->x = $this->lMargin; - } - } - - public function SetXY($x, $y) - { - // Set x and y positions - $this->SetX($x); - $this->SetY($y, false); - } - - public function Output($dest = '', $name = '', $isUTF8 = false) - { - // Output PDF to some destination - $this->Close(); - if (strlen($name) == 1 && strlen($dest) != 1) { - // Fix parameter order - $tmp = $dest; - $dest = $name; - $name = $tmp; - } - if ($dest == '') { - $dest = 'I'; - } - if ($name == '') { - $name = 'doc.pdf'; - } - switch (strtoupper($dest)) { - case 'I': - // Send to standard output - $this->_checkoutput(); - if (PHP_SAPI != 'cli') { - // We send to a browser - header('Content-Type: application/pdf'); - header('Content-Disposition: inline; '.$this->_httpencode('filename', $name, $isUTF8)); - header('Cache-Control: private, max-age=0, must-revalidate'); - header('Pragma: public'); - } - echo $this->buffer; - break; - case 'D': - // Download file - $this->_checkoutput(); - header('Content-Type: application/pdf'); - header('Content-Disposition: attachment; '.$this->_httpencode('filename', $name, $isUTF8)); - header('Cache-Control: private, max-age=0, must-revalidate'); - header('Pragma: public'); - echo $this->buffer; - break; - case 'F': - // Save to local file - if (! file_put_contents($name, $this->buffer)) { - $this->Error('Unable to create output file: '.$name); - } - break; - case 'S': - // Return as a string - return $this->buffer; - default: - $this->Error('Incorrect output destination: '.$dest); - } - - return ''; - } - - /******************************************************************************* - * Protected methods * - *******************************************************************************/ - - protected function _checkoutput() - { - if (PHP_SAPI != 'cli') { - if (headers_sent($file, $line)) { - $this->Error("Some data has already been output, can't send PDF file (output started at $file:$line)"); - } - } - if (ob_get_length()) { - // The output buffer is not empty - if (preg_match('/^(\xEF\xBB\xBF)?\s*$/', ob_get_contents())) { - // It contains only a UTF-8 BOM and/or whitespace, let's clean it - ob_clean(); - } else { - $this->Error("Some data has already been output, can't send PDF file"); - } - } - } - - protected function _getpagesize($size) - { - if (is_string($size)) { - $size = strtolower($size); - if (! isset($this->StdPageSizes[$size])) { - $this->Error('Unknown page size: '.$size); - } - $a = $this->StdPageSizes[$size]; - - return [$a[0] / $this->k, $a[1] / $this->k]; - } else { - if ($size[0] > $size[1]) { - return [$size[1], $size[0]]; - } else { - return $size; - } - } - } - - protected function _beginpage($orientation, $size, $rotation) - { - $this->page++; - $this->pages[$this->page] = ''; - $this->PageLinks[$this->page] = []; - $this->state = 2; - $this->x = $this->lMargin; - $this->y = $this->tMargin; - $this->FontFamily = ''; - // Check page size and orientation - if ($orientation == '') { - $orientation = $this->DefOrientation; - } else { - $orientation = strtoupper($orientation[0]); - } - if ($size == '') { - $size = $this->DefPageSize; - } else { - $size = $this->_getpagesize($size); - } - if ($orientation != $this->CurOrientation || $size[0] != $this->CurPageSize[0] || $size[1] != $this->CurPageSize[1]) { - // New size or orientation - if ($orientation == 'P') { - $this->w = $size[0]; - $this->h = $size[1]; - } else { - $this->w = $size[1]; - $this->h = $size[0]; - } - $this->wPt = $this->w * $this->k; - $this->hPt = $this->h * $this->k; - $this->PageBreakTrigger = $this->h - $this->bMargin; - $this->CurOrientation = $orientation; - $this->CurPageSize = $size; - } - if ($orientation != $this->DefOrientation || $size[0] != $this->DefPageSize[0] || $size[1] != $this->DefPageSize[1]) { - $this->PageInfo[$this->page]['size'] = [$this->wPt, $this->hPt]; - } - if ($rotation != 0) { - if ($rotation % 90 != 0) { - $this->Error('Incorrect rotation value: '.$rotation); - } - $this->PageInfo[$this->page]['rotation'] = $rotation; - } - $this->CurRotation = $rotation; - } - - protected function _endpage() - { - $this->state = 1; - } - - protected function _loadfont($path) - { - // Load a font definition file - include $path; - if (! isset($name)) { - $this->Error('Could not include font definition file: '.$path); - } - if (isset($enc)) { - $enc = strtolower($enc); - } - if (! isset($subsetted)) { - $subsetted = false; - } - - return get_defined_vars(); - } - - protected function _isascii($s) - { - // Test if string is ASCII - $nb = strlen($s); - for ($i = 0; $i < $nb; $i++) { - if (ord($s[$i]) > 127) { - return false; - } - } - - return true; - } - - protected function _httpencode($param, $value, $isUTF8) - { - // Encode HTTP header field parameter - if ($this->_isascii($value)) { - return $param.'="'.$value.'"'; - } - if (! $isUTF8) { - $value = $this->_UTF8encode($value); - } - - return $param."*=UTF-8''".rawurlencode($value); - } - - protected function _UTF8encode($s) - { - // Convert ISO-8859-1 to UTF-8 - if ($this->iconv) { - return iconv('ISO-8859-1', 'UTF-8', $s); - } - $res = ''; - $nb = strlen($s); - for ($i = 0; $i < $nb; $i++) { - $c = $s[$i]; - $v = ord($c); - if ($v >= 128) { - $res .= chr(0xC0 | ($v >> 6)); - $res .= chr(0x80 | ($v & 0x3F)); - } else { - $res .= $c; - } - } - - return $res; - } - - protected function _UTF8toUTF16($s) - { - // Convert UTF-8 to UTF-16BE with BOM - $res = "\xFE\xFF"; - if ($this->iconv) { - return $res.iconv('UTF-8', 'UTF-16BE', $s); - } - $nb = strlen($s); - $i = 0; - while ($i < $nb) { - $c1 = ord($s[$i++]); - if ($c1 >= 224) { - // 3-byte character - $c2 = ord($s[$i++]); - $c3 = ord($s[$i++]); - $res .= chr((($c1 & 0x0F) << 4) + (($c2 & 0x3C) >> 2)); - $res .= chr((($c2 & 0x03) << 6) + ($c3 & 0x3F)); - } elseif ($c1 >= 192) { - // 2-byte character - $c2 = ord($s[$i++]); - $res .= chr(($c1 & 0x1C) >> 2); - $res .= chr((($c1 & 0x03) << 6) + ($c2 & 0x3F)); - } else { - // Single-byte character - $res .= "\0".chr($c1); - } - } - - return $res; - } - - protected function _escape($s) - { - // Escape special characters - if (strpos($s, '(') !== false || strpos($s, ')') !== false || strpos($s, '\\') !== false || strpos($s, "\r") !== false) { - return str_replace(['\\', '(', ')', "\r"], ['\\\\', '\\(', '\\)', '\\r'], $s); - } else { - return $s; - } - } - - protected function _textstring($s) - { - // Format a text string - if (! $this->_isascii($s)) { - $s = $this->_UTF8toUTF16($s); - } - - return '('.$this->_escape($s).')'; - } - - protected function _dounderline($x, $y, $txt) - { - // Underline text - $up = $this->CurrentFont['up']; - $ut = $this->CurrentFont['ut']; - $w = $this->GetStringWidth($txt) + $this->ws * substr_count($txt, ' '); - - return sprintf('%.2F %.2F %.2F %.2F re f', $x * $this->k, ($this->h - ($y - $up / 1000 * $this->FontSize)) * $this->k, $w * $this->k, -$ut / 1000 * $this->FontSizePt); - } - - protected function _parsejpg($file) - { - // Extract info from a JPEG file - $a = getimagesize($file); - if (! $a) { - $this->Error('Missing or incorrect image file: '.$file); - } - if ($a[2] != 2) { - $this->Error('Not a JPEG file: '.$file); - } - if (! isset($a['channels']) || $a['channels'] == 3) { - $colspace = 'DeviceRGB'; - } elseif ($a['channels'] == 4) { - $colspace = 'DeviceCMYK'; - } else { - $colspace = 'DeviceGray'; - } - $bpc = isset($a['bits']) ? $a['bits'] : 8; - $data = file_get_contents($file); - - return ['w' => $a[0], 'h' => $a[1], 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'DCTDecode', 'data' => $data]; - } - - protected function _parsepng($file) - { - // Extract info from a PNG file - $f = fopen($file, 'rb'); - if (! $f) { - $this->Error('Can\'t open image file: '.$file); - } - $info = $this->_parsepngstream($f, $file); - fclose($f); - - return $info; - } - - protected function _parsepngstream($f, $file) - { - // Check signature - if ($this->_readstream($f, 8) != chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) { - $this->Error('Not a PNG file: '.$file); - } - - // Read header chunk - $this->_readstream($f, 4); - if ($this->_readstream($f, 4) != 'IHDR') { - $this->Error('Incorrect PNG file: '.$file); - } - $w = $this->_readint($f); - $h = $this->_readint($f); - $bpc = ord($this->_readstream($f, 1)); - if ($bpc > 8) { - $this->Error('16-bit depth not supported: '.$file); - } - $ct = ord($this->_readstream($f, 1)); - if ($ct == 0 || $ct == 4) { - $colspace = 'DeviceGray'; - } elseif ($ct == 2 || $ct == 6) { - $colspace = 'DeviceRGB'; - } elseif ($ct == 3) { - $colspace = 'Indexed'; - } else { - $this->Error('Unknown color type: '.$file); - } - if (ord($this->_readstream($f, 1)) != 0) { - $this->Error('Unknown compression method: '.$file); - } - if (ord($this->_readstream($f, 1)) != 0) { - $this->Error('Unknown filter method: '.$file); - } - if (ord($this->_readstream($f, 1)) != 0) { - $this->Error('Interlacing not supported: '.$file); - } - $this->_readstream($f, 4); - $dp = '/Predictor 15 /Colors '.($colspace == 'DeviceRGB' ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w; - - // Scan chunks looking for palette, transparency and image data - $pal = ''; - $trns = ''; - $data = ''; - do { - $n = $this->_readint($f); - $type = $this->_readstream($f, 4); - if ($type == 'PLTE') { - // Read palette - $pal = $this->_readstream($f, $n); - $this->_readstream($f, 4); - } elseif ($type == 'tRNS') { - // Read transparency info - $t = $this->_readstream($f, $n); - if ($ct == 0) { - $trns = [ord(substr($t, 1, 1))]; - } elseif ($ct == 2) { - $trns = [ord(substr($t, 1, 1)), ord(substr($t, 3, 1)), ord(substr($t, 5, 1))]; - } else { - $pos = strpos($t, chr(0)); - if ($pos !== false) { - $trns = [$pos]; - } - } - $this->_readstream($f, 4); - } elseif ($type == 'IDAT') { - // Read image data block - $data .= $this->_readstream($f, $n); - $this->_readstream($f, 4); - } elseif ($type == 'IEND') { - break; - } else { - $this->_readstream($f, $n + 4); - } - } while ($n); - - if ($colspace == 'Indexed' && empty($pal)) { - $this->Error('Missing palette in '.$file); - } - $info = ['w' => $w, 'h' => $h, 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'FlateDecode', 'dp' => $dp, 'pal' => $pal, 'trns' => $trns]; - if ($ct >= 4) { - // Extract alpha channel - if (! function_exists('gzuncompress')) { - $this->Error('Zlib not available, can\'t handle alpha channel: '.$file); - } - $data = gzuncompress($data); - $color = ''; - $alpha = ''; - if ($ct == 4) { - // Gray image - $len = 2 * $w; - for ($i = 0; $i < $h; $i++) { - $pos = (1 + $len) * $i; - $color .= $data[$pos]; - $alpha .= $data[$pos]; - $line = substr($data, $pos + 1, $len); - $color .= preg_replace('/(.)./s', '$1', $line); - $alpha .= preg_replace('/.(.)/s', '$1', $line); - } - } else { - // RGB image - $len = 4 * $w; - for ($i = 0; $i < $h; $i++) { - $pos = (1 + $len) * $i; - $color .= $data[$pos]; - $alpha .= $data[$pos]; - $line = substr($data, $pos + 1, $len); - $color .= preg_replace('/(.{3})./s', '$1', $line); - $alpha .= preg_replace('/.{3}(.)/s', '$1', $line); - } - } - unset($data); - $data = gzcompress($color); - $info['smask'] = gzcompress($alpha); - $this->WithAlpha = true; - if ($this->PDFVersion < '1.4') { - $this->PDFVersion = '1.4'; - } - } - $info['data'] = $data; - - return $info; - } - - protected function _readstream($f, $n) - { - // Read n bytes from stream - $res = ''; - while ($n > 0 && ! feof($f)) { - $s = fread($f, $n); - if ($s === false) { - $this->Error('Error while reading stream'); - } - $n -= strlen($s); - $res .= $s; - } - if ($n > 0) { - $this->Error('Unexpected end of stream'); - } - - return $res; - } - - protected function _readint($f) - { - // Read a 4-byte integer from stream - $a = unpack('Ni', $this->_readstream($f, 4)); - - return $a['i']; - } - - protected function _parsegif($file) - { - // Extract info from a GIF file (via PNG conversion) - if (! function_exists('imagepng')) { - $this->Error('GD extension is required for GIF support'); - } - if (! function_exists('imagecreatefromgif')) { - $this->Error('GD has no GIF read support'); - } - $im = imagecreatefromgif($file); - if (! $im) { - $this->Error('Missing or incorrect image file: '.$file); - } - imageinterlace($im, 0); - ob_start(); - imagepng($im); - $data = ob_get_clean(); - imagedestroy($im); - $f = fopen('php://temp', 'rb+'); - if (! $f) { - $this->Error('Unable to create memory stream'); - } - fwrite($f, $data); - rewind($f); - $info = $this->_parsepngstream($f, $file); - fclose($f); - - return $info; - } - - protected function _out($s) - { - // Add a line to the current page - if ($this->state == 2) { - $this->pages[$this->page] .= $s."\n"; - } elseif ($this->state == 0) { - $this->Error('No page has been added yet'); - } elseif ($this->state == 1) { - $this->Error('Invalid call'); - } elseif ($this->state == 3) { - $this->Error('The document is closed'); - } - } - - protected function _put($s) - { - // Add a line to the document - $this->buffer .= $s."\n"; - } - - protected function _getoffset() - { - return strlen($this->buffer); - } - - protected function _newobj($n = null) - { - // Begin a new object - if ($n === null) { - $n = ++$this->n; - } - $this->offsets[$n] = $this->_getoffset(); - $this->_put($n.' 0 obj'); - } - - protected function _putstream($data) - { - $this->_put('stream'); - $this->_put($data); - $this->_put('endstream'); - } - - protected function _putstreamobject($data) - { - if ($this->compress) { - $entries = '/Filter /FlateDecode '; - $data = gzcompress($data); - } else { - $entries = ''; - } - $entries .= '/Length '.strlen($data); - $this->_newobj(); - $this->_put('<<'.$entries.'>>'); - $this->_putstream($data); - $this->_put('endobj'); - } - - protected function _putlinks($n) - { - foreach ($this->PageLinks[$n] as $pl) { - $this->_newobj(); - $rect = sprintf('%.2F %.2F %.2F %.2F', $pl[0], $pl[1], $pl[0] + $pl[2], $pl[1] - $pl[3]); - $s = '<_textstring($pl[4]).'>>>>'; - } else { - $l = $this->links[$pl[4]]; - if (isset($this->PageInfo[$l[0]]['size'])) { - $h = $this->PageInfo[$l[0]]['size'][1]; - } else { - $h = ($this->DefOrientation == 'P') ? $this->DefPageSize[1] * $this->k : $this->DefPageSize[0] * $this->k; - } - $s .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>', $this->PageInfo[$l[0]]['n'], $h - $l[1] * $this->k); - } - $this->_put($s); - $this->_put('endobj'); - } - } - - protected function _putpage($n) - { - $this->_newobj(); - $this->_put('<_put('/Parent 1 0 R'); - if (isset($this->PageInfo[$n]['size'])) { - $this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]', $this->PageInfo[$n]['size'][0], $this->PageInfo[$n]['size'][1])); - } - if (isset($this->PageInfo[$n]['rotation'])) { - $this->_put('/Rotate '.$this->PageInfo[$n]['rotation']); - } - $this->_put('/Resources 2 0 R'); - if (! empty($this->PageLinks[$n])) { - $s = '/Annots ['; - foreach ($this->PageLinks[$n] as $pl) { - $s .= $pl[5].' 0 R '; - } - $s .= ']'; - $this->_put($s); - } - if ($this->WithAlpha) { - $this->_put('/Group <>'); - } - $this->_put('/Contents '.($this->n + 1).' 0 R>>'); - $this->_put('endobj'); - // Page content - if (! empty($this->AliasNbPages)) { - $this->pages[$n] = str_replace($this->AliasNbPages, $this->page, $this->pages[$n]); - } - $this->_putstreamobject($this->pages[$n]); - // Link annotations - $this->_putlinks($n); - } - - protected function _putpages() - { - $nb = $this->page; - $n = $this->n; - for ($i = 1; $i <= $nb; $i++) { - $this->PageInfo[$i]['n'] = ++$n; - $n++; - foreach ($this->PageLinks[$i] as &$pl) { - $pl[5] = ++$n; - } - unset($pl); - } - for ($i = 1; $i <= $nb; $i++) { - $this->_putpage($i); - } - // Pages root - $this->_newobj(1); - $this->_put('<PageInfo[$i]['n'].' 0 R '; - } - $kids .= ']'; - $this->_put($kids); - $this->_put('/Count '.$nb); - if ($this->DefOrientation == 'P') { - $w = $this->DefPageSize[0]; - $h = $this->DefPageSize[1]; - } else { - $w = $this->DefPageSize[1]; - $h = $this->DefPageSize[0]; - } - $this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]', $w * $this->k, $h * $this->k)); - $this->_put('>>'); - $this->_put('endobj'); - } - - protected function _putfonts() - { - foreach ($this->FontFiles as $file => $info) { - // Font file embedding - $this->_newobj(); - $this->FontFiles[$file]['n'] = $this->n; - $font = file_get_contents($file); - if (! $font) { - $this->Error('Font file not found: '.$file); - } - $compressed = (substr($file, -2) == '.z'); - if (! $compressed && isset($info['length2'])) { - $font = substr($font, 6, $info['length1']).substr($font, 6 + $info['length1'] + 6, $info['length2']); - } - $this->_put('<_put('/Filter /FlateDecode'); - } - $this->_put('/Length1 '.$info['length1']); - if (isset($info['length2'])) { - $this->_put('/Length2 '.$info['length2'].' /Length3 0'); - } - $this->_put('>>'); - $this->_putstream($font); - $this->_put('endobj'); - } - foreach ($this->fonts as $k => $font) { - // Encoding - if (isset($font['diff'])) { - if (! isset($this->encodings[$font['enc']])) { - $this->_newobj(); - $this->_put('<>'); - $this->_put('endobj'); - $this->encodings[$font['enc']] = $this->n; - } - } - // ToUnicode CMap - if (isset($font['uv'])) { - if (isset($font['enc'])) { - $cmapkey = $font['enc']; - } else { - $cmapkey = $font['name']; - } - if (! isset($this->cmaps[$cmapkey])) { - $cmap = $this->_tounicodecmap($font['uv']); - $this->_putstreamobject($cmap); - $this->cmaps[$cmapkey] = $this->n; - } - } - // Font object - $this->fonts[$k]['n'] = $this->n + 1; - $type = $font['type']; - $name = $font['name']; - if ($font['subsetted']) { - $name = 'AAAAAA+'.$name; - } - if ($type == 'Core') { - // Core font - $this->_newobj(); - $this->_put('<_put('/BaseFont /'.$name); - $this->_put('/Subtype /Type1'); - if ($name != 'Symbol' && $name != 'ZapfDingbats') { - $this->_put('/Encoding /WinAnsiEncoding'); - } - if (isset($font['uv'])) { - $this->_put('/ToUnicode '.$this->cmaps[$cmapkey].' 0 R'); - } - $this->_put('>>'); - $this->_put('endobj'); - } elseif ($type == 'Type1' || $type == 'TrueType') { - // Additional Type1 or TrueType/OpenType font - $this->_newobj(); - $this->_put('<_put('/BaseFont /'.$name); - $this->_put('/Subtype /'.$type); - $this->_put('/FirstChar 32 /LastChar 255'); - $this->_put('/Widths '.($this->n + 1).' 0 R'); - $this->_put('/FontDescriptor '.($this->n + 2).' 0 R'); - if (isset($font['diff'])) { - $this->_put('/Encoding '.$this->encodings[$font['enc']].' 0 R'); - } else { - $this->_put('/Encoding /WinAnsiEncoding'); - } - if (isset($font['uv'])) { - $this->_put('/ToUnicode '.$this->cmaps[$cmapkey].' 0 R'); - } - $this->_put('>>'); - $this->_put('endobj'); - // Widths - $this->_newobj(); - $cw = $font['cw']; - $s = '['; - for ($i = 32; $i <= 255; $i++) { - $s .= $cw[chr($i)].' '; - } - $this->_put($s.']'); - $this->_put('endobj'); - // Descriptor - $this->_newobj(); - $s = '< $v) { - $s .= ' /'.$k.' '.$v; - } - if (! empty($font['file'])) { - $s .= ' /FontFile'.($type == 'Type1' ? '' : '2').' '.$this->FontFiles[$font['file']]['n'].' 0 R'; - } - $this->_put($s.'>>'); - $this->_put('endobj'); - } else { - // Allow for additional types - $mtd = '_put'.strtolower($type); - if (! method_exists($this, $mtd)) { - $this->Error('Unsupported font type: '.$type); - } - $this->$mtd($font); - } - } - } - - protected function _tounicodecmap($uv) - { - $ranges = ''; - $nbr = 0; - $chars = ''; - $nbc = 0; - foreach ($uv as $c => $v) { - if (is_array($v)) { - $ranges .= sprintf("<%02X> <%02X> <%04X>\n", $c, $c + $v[1] - 1, $v[0]); - $nbr++; - } else { - $chars .= sprintf("<%02X> <%04X>\n", $c, $v); - $nbc++; - } - } - $s = "/CIDInit /ProcSet findresource begin\n"; - $s .= "12 dict begin\n"; - $s .= "begincmap\n"; - $s .= "/CIDSystemInfo\n"; - $s .= "< 0) { - $s .= "$nbr beginbfrange\n"; - $s .= $ranges; - $s .= "endbfrange\n"; - } - if ($nbc > 0) { - $s .= "$nbc beginbfchar\n"; - $s .= $chars; - $s .= "endbfchar\n"; - } - $s .= "endcmap\n"; - $s .= "CMapName currentdict /CMap defineresource pop\n"; - $s .= "end\n"; - $s .= 'end'; - - return $s; - } - - protected function _putimages() - { - foreach (array_keys($this->images) as $file) { - $this->_putimage($this->images[$file]); - unset($this->images[$file]['data']); - unset($this->images[$file]['smask']); - } - } - - protected function _putimage(&$info) - { - $this->_newobj(); - $info['n'] = $this->n; - $this->_put('<_put('/Subtype /Image'); - $this->_put('/Width '.$info['w']); - $this->_put('/Height '.$info['h']); - if ($info['cs'] == 'Indexed') { - $this->_put('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal']) / 3 - 1).' '.($this->n + 1).' 0 R]'); - } else { - $this->_put('/ColorSpace /'.$info['cs']); - if ($info['cs'] == 'DeviceCMYK') { - $this->_put('/Decode [1 0 1 0 1 0 1 0]'); - } - } - $this->_put('/BitsPerComponent '.$info['bpc']); - if (isset($info['f'])) { - $this->_put('/Filter /'.$info['f']); - } - if (isset($info['dp'])) { - $this->_put('/DecodeParms <<'.$info['dp'].'>>'); - } - if (isset($info['trns']) && is_array($info['trns'])) { - $trns = ''; - for ($i = 0; $i < count($info['trns']); $i++) { - $trns .= $info['trns'][$i].' '.$info['trns'][$i].' '; - } - $this->_put('/Mask ['.$trns.']'); - } - if (isset($info['smask'])) { - $this->_put('/SMask '.($this->n + 1).' 0 R'); - } - $this->_put('/Length '.strlen($info['data']).'>>'); - $this->_putstream($info['data']); - $this->_put('endobj'); - // Soft mask - if (isset($info['smask'])) { - $dp = '/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns '.$info['w']; - $smask = ['w' => $info['w'], 'h' => $info['h'], 'cs' => 'DeviceGray', 'bpc' => 8, 'f' => $info['f'], 'dp' => $dp, 'data' => $info['smask']]; - $this->_putimage($smask); - } - // Palette - if ($info['cs'] == 'Indexed') { - $this->_putstreamobject($info['pal']); - } - } - - protected function _putxobjectdict() - { - foreach ($this->images as $image) { - $this->_put('/I'.$image['i'].' '.$image['n'].' 0 R'); - } - } - - protected function _putresourcedict() - { - $this->_put('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); - $this->_put('/Font <<'); - foreach ($this->fonts as $font) { - $this->_put('/F'.$font['i'].' '.$font['n'].' 0 R'); - } - $this->_put('>>'); - $this->_put('/XObject <<'); - $this->_putxobjectdict(); - $this->_put('>>'); - } - - protected function _putresources() - { - $this->_putfonts(); - $this->_putimages(); - // Resource dictionary - $this->_newobj(2); - $this->_put('<<'); - $this->_putresourcedict(); - $this->_put('>>'); - $this->_put('endobj'); - } - - protected function _putinfo() - { - $date = @date('YmdHisO', $this->CreationDate); - $this->metadata['CreationDate'] = 'D:'.substr($date, 0, -2)."'".substr($date, -2)."'"; - foreach ($this->metadata as $key => $value) { - $this->_put('/'.$key.' '.$this->_textstring($value)); - } - } - - protected function _putcatalog() - { - $n = $this->PageInfo[1]['n']; - $this->_put('/Type /Catalog'); - $this->_put('/Pages 1 0 R'); - if ($this->ZoomMode == 'fullpage') { - $this->_put('/OpenAction ['.$n.' 0 R /Fit]'); - } elseif ($this->ZoomMode == 'fullwidth') { - $this->_put('/OpenAction ['.$n.' 0 R /FitH null]'); - } elseif ($this->ZoomMode == 'real') { - $this->_put('/OpenAction ['.$n.' 0 R /XYZ null null 1]'); - } elseif (! is_string($this->ZoomMode)) { - $this->_put('/OpenAction ['.$n.' 0 R /XYZ null null '.sprintf('%.2F', $this->ZoomMode / 100).']'); - } - if ($this->LayoutMode == 'single') { - $this->_put('/PageLayout /SinglePage'); - } elseif ($this->LayoutMode == 'continuous') { - $this->_put('/PageLayout /OneColumn'); - } elseif ($this->LayoutMode == 'two') { - $this->_put('/PageLayout /TwoColumnLeft'); - } - } - - protected function _putheader() - { - $this->_put('%PDF-'.$this->PDFVersion); - } - - protected function _puttrailer() - { - $this->_put('/Size '.($this->n + 1)); - $this->_put('/Root '.$this->n.' 0 R'); - $this->_put('/Info '.($this->n - 1).' 0 R'); - } - - protected function _enddoc() - { - $this->CreationDate = time(); - $this->_putheader(); - $this->_putpages(); - $this->_putresources(); - // Info - $this->_newobj(); - $this->_put('<<'); - $this->_putinfo(); - $this->_put('>>'); - $this->_put('endobj'); - // Catalog - $this->_newobj(); - $this->_put('<<'); - $this->_putcatalog(); - $this->_put('>>'); - $this->_put('endobj'); - // Cross-ref - $offset = $this->_getoffset(); - $this->_put('xref'); - $this->_put('0 '.($this->n + 1)); - $this->_put('0000000000 65535 f '); - for ($i = 1; $i <= $this->n; $i++) { - $this->_put(sprintf('%010d 00000 n ', $this->offsets[$i])); - } - // Trailer - $this->_put('trailer'); - $this->_put('<<'); - $this->_puttrailer(); - $this->_put('>>'); - $this->_put('startxref'); - $this->_put($offset); - $this->_put('%%EOF'); - $this->state = 3; - } -} + const VERSION = '1.86'; + protected $page; // current page number + protected $n; // current object number + protected $offsets; // array of object offsets + protected $buffer; // buffer holding in-memory PDF + protected $pages; // array containing pages + protected $state; // current document state + protected $compress; // compression flag + protected $iconv; // whether iconv is available + protected $k; // scale factor (number of points in user unit) + protected $DefOrientation; // default orientation + protected $CurOrientation; // current orientation + protected $StdPageSizes; // standard page sizes + protected $DefPageSize; // default page size + protected $CurPageSize; // current page size + protected $CurRotation; // current page rotation + protected $PageInfo; // page-related data + protected $wPt, $hPt; // dimensions of current page in points + protected $w, $h; // dimensions of current page in user unit + protected $lMargin; // left margin + protected $tMargin; // top margin + protected $rMargin; // right margin + protected $bMargin; // page break margin + protected $cMargin; // cell margin + protected $x, $y; // current position in user unit + protected $lasth; // height of last printed cell + protected $LineWidth; // line width in user unit + protected $fontpath; // directory containing fonts + protected $CoreFonts; // array of core font names + protected $fonts; // array of used fonts + protected $FontFiles; // array of font files + protected $encodings; // array of encodings + protected $cmaps; // array of ToUnicode CMaps + protected $FontFamily; // current font family + protected $FontStyle; // current font style + protected $underline; // underlining flag + protected $CurrentFont; // current font info + protected $FontSizePt; // current font size in points + protected $FontSize; // current font size in user unit + protected $DrawColor; // commands for drawing color + protected $FillColor; // commands for filling color + protected $TextColor; // commands for text color + protected $ColorFlag; // indicates whether fill and text colors are different + protected $WithAlpha; // indicates whether alpha channel is used + protected $ws; // word spacing + protected $images; // array of used images + protected $PageLinks; // array of links in pages + protected $links; // array of internal links + protected $AutoPageBreak; // automatic page breaking + protected $PageBreakTrigger; // threshold used to trigger page breaks + protected $InHeader; // flag set when processing header + protected $InFooter; // flag set when processing footer + protected $AliasNbPages; // alias for total number of pages + protected $ZoomMode; // zoom display mode + protected $LayoutMode; // layout display mode + protected $metadata; // document properties + protected $CreationDate; // document creation date + protected $PDFVersion; // PDF version number + + /******************************************************************************* + * Public methods * + *******************************************************************************/ + + function __construct($orientation = 'P', $unit = 'mm', $size = 'A4') + { + // FIXED: Set font path directly + $this->fontpath = __DIR__ . '/font/'; + + // Initialization of properties + $this->state = 0; + $this->page = 0; + $this->n = 2; + $this->buffer = ''; + $this->pages = array(); + $this->PageInfo = array(); + $this->fonts = array(); + $this->FontFiles = array(); + $this->encodings = array(); + $this->cmaps = array(); + $this->images = array(); + $this->links = array(); + $this->InHeader = false; + $this->InFooter = false; + $this->lasth = 0; + $this->FontFamily = ''; + $this->FontStyle = ''; + $this->FontSizePt = 12; + $this->underline = false; + $this->DrawColor = '0 G'; + $this->FillColor = '0 g'; + $this->TextColor = '0 g'; + $this->ColorFlag = false; + $this->WithAlpha = false; + $this->ws = 0; + $this->iconv = function_exists('iconv'); + + // Core fonts + $this->CoreFonts = array('courier', 'helvetica', 'times', 'symbol', 'zapfdingbats'); + + // Scale factor + if ($unit == 'pt') + $this->k = 1; + elseif ($unit == 'mm') + $this->k = 72 / 25.4; + elseif ($unit == 'cm') + $this->k = 72 / 2.54; + elseif ($unit == 'in') + $this->k = 72; + else + $this->Error('Incorrect unit: ' . $unit); + + // Page sizes + $this->StdPageSizes = array( + 'a3' => array(841.89, 1190.55), + 'a4' => array(595.28, 841.89), + 'a5' => array(420.94, 595.28), + 'letter' => array(612, 792), + 'legal' => array(612, 1008) + ); + $size = $this->_getpagesize($size); + $this->DefPageSize = $size; + $this->CurPageSize = $size; + + // Page orientation + $orientation = strtolower($orientation); + if ($orientation == 'p' || $orientation == 'portrait') { + $this->DefOrientation = 'P'; + $this->w = $size[0]; + $this->h = $size[1]; + } elseif ($orientation == 'l' || $orientation == 'landscape') { + $this->DefOrientation = 'L'; + $this->w = $size[1]; + $this->h = $size[0]; + } else { + $this->Error('Incorrect orientation: ' . $orientation); + } + $this->CurOrientation = $this->DefOrientation; + $this->wPt = $this->w * $this->k; + $this->hPt = $this->h * $this->k; + + // Page rotation + $this->CurRotation = 0; + + // Margins + $margin = 28.35 / $this->k; + $this->SetMargins($margin, $margin); + $this->cMargin = $margin / 10; + $this->LineWidth = .567 / $this->k; + + // Page break + $this->SetAutoPageBreak(true, 2 * $margin); + + // Display and compression + $this->SetDisplayMode('default'); + $this->SetCompression(true); + + // Metadata + $this->metadata = array('Producer' => 'FPDF ' . self::VERSION); + $this->PDFVersion = '1.3'; + } + + + function SetMargins($left, $top, $right = null) + { + // Set left, top and right margins + $this->lMargin = $left; + $this->tMargin = $top; + if ($right === null) + $right = $left; + $this->rMargin = $right; + } + + function SetLeftMargin($margin) + { + // Set left margin + $this->lMargin = $margin; + if ($this->page > 0 && $this->x < $margin) + $this->x = $margin; + } + + function SetTopMargin($margin) + { + // Set top margin + $this->tMargin = $margin; + } + + function SetRightMargin($margin) + { + // Set right margin + $this->rMargin = $margin; + } + + function SetAutoPageBreak($auto, $margin = 0) + { + // Set auto page break mode and triggering margin + $this->AutoPageBreak = $auto; + $this->bMargin = $margin; + $this->PageBreakTrigger = $this->h - $margin; + } + + function SetDisplayMode($zoom, $layout = 'default') + { + // Set display mode in viewer + if ($zoom == 'fullpage' || $zoom == 'fullwidth' || $zoom == 'real' || $zoom == 'default' || !is_string($zoom)) + $this->ZoomMode = $zoom; + else + $this->Error('Incorrect zoom display mode: ' . $zoom); + if ($layout == 'single' || $layout == 'continuous' || $layout == 'two' || $layout == 'default') + $this->LayoutMode = $layout; + else + $this->Error('Incorrect layout display mode: ' . $layout); + } + + function SetCompression($compress) + { + // Set page compression + if (function_exists('gzcompress')) + $this->compress = $compress; + else + $this->compress = false; + } + + function SetTitle($title, $isUTF8 = false) + { + // Title of document + $this->metadata['Title'] = $isUTF8 ? $title : $this->_UTF8encode($title); + } + + function SetAuthor($author, $isUTF8 = false) + { + // Author of document + $this->metadata['Author'] = $isUTF8 ? $author : $this->_UTF8encode($author); + } + + function SetSubject($subject, $isUTF8 = false) + { + // Subject of document + $this->metadata['Subject'] = $isUTF8 ? $subject : $this->_UTF8encode($subject); + } + + function SetKeywords($keywords, $isUTF8 = false) + { + // Keywords of document + $this->metadata['Keywords'] = $isUTF8 ? $keywords : $this->_UTF8encode($keywords); + } + + function SetCreator($creator, $isUTF8 = false) + { + // Creator of document + $this->metadata['Creator'] = $isUTF8 ? $creator : $this->_UTF8encode($creator); + } + + function AliasNbPages($alias = '{nb}') + { + // Define an alias for total number of pages + $this->AliasNbPages = $alias; + } + + function Error($msg) + { + // Fatal error + throw new Exception('FPDF error: ' . $msg); + } + + function Close() + { + // Terminate document + if ($this->state == 3) + return; + if ($this->page == 0) + $this->AddPage(); + // Page footer + $this->InFooter = true; + $this->Footer(); + $this->InFooter = false; + // Close page + $this->_endpage(); + // Close document + $this->_enddoc(); + } + + function AddPage($orientation = '', $size = '', $rotation = 0) + { + // Start a new page + if ($this->state == 3) + $this->Error('The document is closed'); + $family = $this->FontFamily; + $style = $this->FontStyle . ($this->underline ? 'U' : ''); + $fontsize = $this->FontSizePt; + $lw = $this->LineWidth; + $dc = $this->DrawColor; + $fc = $this->FillColor; + $tc = $this->TextColor; + $cf = $this->ColorFlag; + if ($this->page > 0) { + // Page footer + $this->InFooter = true; + $this->Footer(); + $this->InFooter = false; + // Close page + $this->_endpage(); + } + // Start new page + $this->_beginpage($orientation, $size, $rotation); + // Set line cap style to square + $this->_out('2 J'); + // Set line width + $this->LineWidth = $lw; + $this->_out(sprintf('%.2F w', $lw * $this->k)); + // Set font + if ($family) + $this->SetFont($family, $style, $fontsize); + // Set colors + $this->DrawColor = $dc; + if ($dc != '0 G') + $this->_out($dc); + $this->FillColor = $fc; + if ($fc != '0 g') + $this->_out($fc); + $this->TextColor = $tc; + $this->ColorFlag = $cf; + // Page header + $this->InHeader = true; + $this->Header(); + $this->InHeader = false; + // Restore line width + if ($this->LineWidth != $lw) { + $this->LineWidth = $lw; + $this->_out(sprintf('%.2F w', $lw * $this->k)); + } + // Restore font + if ($family) + $this->SetFont($family, $style, $fontsize); + // Restore colors + if ($this->DrawColor != $dc) { + $this->DrawColor = $dc; + $this->_out($dc); + } + if ($this->FillColor != $fc) { + $this->FillColor = $fc; + $this->_out($fc); + } + $this->TextColor = $tc; + $this->ColorFlag = $cf; + } + + function Header() + { + // To be implemented in your own inherited class + } + + function Footer() + { + // To be implemented in your own inherited class + } + + function PageNo() + { + // Get current page number + return $this->page; + } + + function SetDrawColor($r, $g = null, $b = null) + { + // Set color for all stroking operations + if (($r == 0 && $g == 0 && $b == 0) || $g === null) + $this->DrawColor = sprintf('%.3F G', $r / 255); + else + $this->DrawColor = sprintf('%.3F %.3F %.3F RG', $r / 255, $g / 255, $b / 255); + if ($this->page > 0) + $this->_out($this->DrawColor); + } + + function SetFillColor($r, $g = null, $b = null) + { + // Set color for all filling operations + if (($r == 0 && $g == 0 && $b == 0) || $g === null) + $this->FillColor = sprintf('%.3F g', $r / 255); + else + $this->FillColor = sprintf('%.3F %.3F %.3F rg', $r / 255, $g / 255, $b / 255); + $this->ColorFlag = ($this->FillColor != $this->TextColor); + if ($this->page > 0) + $this->_out($this->FillColor); + } + + function SetTextColor($r, $g = null, $b = null) + { + // Set color for text + if (($r == 0 && $g == 0 && $b == 0) || $g === null) + $this->TextColor = sprintf('%.3F g', $r / 255); + else + $this->TextColor = sprintf('%.3F %.3F %.3F rg', $r / 255, $g / 255, $b / 255); + $this->ColorFlag = ($this->FillColor != $this->TextColor); + } + + function GetStringWidth($s) + { + // Get width of a string in the current font + $cw = $this->CurrentFont['cw']; + $w = 0; + $s = (string)$s; + $l = strlen($s); + for ($i = 0; $i < $l; $i++) + $w += $cw[$s[$i]]; + return $w * $this->FontSize / 1000; + } + + function SetLineWidth($width) + { + // Set line width + $this->LineWidth = $width; + if ($this->page > 0) + $this->_out(sprintf('%.2F w', $width * $this->k)); + } + + function Line($x1, $y1, $x2, $y2) + { + // Draw a line + $this->_out(sprintf('%.2F %.2F m %.2F %.2F l S', $x1 * $this->k, ($this->h - $y1) * $this->k, $x2 * $this->k, ($this->h - $y2) * $this->k)); + } + + function Rect($x, $y, $w, $h, $style = '') + { + // Draw a rectangle + if ($style == 'F') + $op = 'f'; + elseif ($style == 'FD' || $style == 'DF') + $op = 'B'; + else + $op = 'S'; + $this->_out(sprintf('%.2F %.2F %.2F %.2F re %s', $x * $this->k, ($this->h - $y) * $this->k, $w * $this->k, -$h * $this->k, $op)); + } + + function AddFont($family, $style = '', $file = '', $dir = '') + { + // Add a TrueType, OpenType or Type1 font + $family = strtolower($family); + if ($file == '') + $file = str_replace(' ', '', $family) . strtolower($style) . '.php'; + $style = strtoupper($style); + if ($style == 'IB') + $style = 'BI'; + $fontkey = $family . $style; + if (isset($this->fonts[$fontkey])) + return; + if (strpos($file, '/') !== false || strpos($file, "\\") !== false) + $this->Error('Incorrect font definition file name: ' . $file); + if ($dir == '') + $dir = $this->fontpath; + if (substr($dir, -1) != '/' && substr($dir, -1) != '\\') + $dir .= '/'; + $info = $this->_loadfont($dir . $file); + $info['i'] = count($this->fonts) + 1; + if (!empty($info['file'])) { + // Embedded font + $info['file'] = $dir . $info['file']; + if ($info['type'] == 'TrueType') + $this->FontFiles[$info['file']] = array('length1' => $info['originalsize']); + else + $this->FontFiles[$info['file']] = array('length1' => $info['size1'], 'length2' => $info['size2']); + } + $this->fonts[$fontkey] = $info; + } + + function SetFont($family, $style = '', $size = 0) + { + // Select a font; size given in points + if ($family == '') + $family = $this->FontFamily; + else + $family = strtolower($family); + $style = strtoupper($style); + if (strpos($style, 'U') !== false) { + $this->underline = true; + $style = str_replace('U', '', $style); + } else + $this->underline = false; + if ($style == 'IB') + $style = 'BI'; + if ($size == 0) + $size = $this->FontSizePt; + // Test if font is already selected + if ($this->FontFamily == $family && $this->FontStyle == $style && $this->FontSizePt == $size) + return; + // Test if font is already loaded + $fontkey = $family . $style; + if (!isset($this->fonts[$fontkey])) { + // Test if one of the core fonts + if ($family == 'arial') + $family = 'helvetica'; + if (in_array($family, $this->CoreFonts)) { + if ($family == 'symbol' || $family == 'zapfdingbats') + $style = ''; + $fontkey = $family . $style; + if (!isset($this->fonts[$fontkey])) + $this->AddFont($family, $style); + } else + $this->Error('Undefined font: ' . $family . ' ' . $style); + } + // Select it + $this->FontFamily = $family; + $this->FontStyle = $style; + $this->FontSizePt = $size; + $this->FontSize = $size / $this->k; + $this->CurrentFont = $this->fonts[$fontkey]; + if ($this->page > 0) + $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); + } + + function SetFontSize($size) + { + // Set font size in points + if ($this->FontSizePt == $size) + return; + $this->FontSizePt = $size; + $this->FontSize = $size / $this->k; + if ($this->page > 0 && isset($this->CurrentFont)) + $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); + } + + function AddLink() + { + // Create a new internal link + $n = count($this->links) + 1; + $this->links[$n] = array(0, 0); + return $n; + } + + function SetLink($link, $y = 0, $page = -1) + { + // Set destination of internal link + if ($y == -1) + $y = $this->y; + if ($page == -1) + $page = $this->page; + $this->links[$link] = array($page, $y); + } + + function Link($x, $y, $w, $h, $link) + { + // Put a link on the page + $this->PageLinks[$this->page][] = array($x * $this->k, $this->hPt - $y * $this->k, $w * $this->k, $h * $this->k, $link); + } + + function Text($x, $y, $txt) + { + // Output a string + if (!isset($this->CurrentFont)) + $this->Error('No font has been set'); + $txt = (string)$txt; + $s = sprintf('BT %.2F %.2F Td (%s) Tj ET', $x * $this->k, ($this->h - $y) * $this->k, $this->_escape($txt)); + if ($this->underline && $txt !== '') + $s .= ' ' . $this->_dounderline($x, $y, $txt); + if ($this->ColorFlag) + $s = 'q ' . $this->TextColor . ' ' . $s . ' Q'; + $this->_out($s); + } + + function AcceptPageBreak() + { + // Accept automatic page break or not + return $this->AutoPageBreak; + } + + function Cell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = false, $link = '') + { + // Output a cell + $k = $this->k; + if ($this->y + $h > $this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak()) { + // Automatic page break + $x = $this->x; + $ws = $this->ws; + if ($ws > 0) { + $this->ws = 0; + $this->_out('0 Tw'); + } + $this->AddPage($this->CurOrientation, $this->CurPageSize, $this->CurRotation); + $this->x = $x; + if ($ws > 0) { + $this->ws = $ws; + $this->_out(sprintf('%.3F Tw', $ws * $k)); + } + } + if ($w == 0) + $w = $this->w - $this->rMargin - $this->x; + $s = ''; + if ($fill || $border == 1) { + if ($fill) + $op = ($border == 1) ? 'B' : 'f'; + else + $op = 'S'; + $s = sprintf('%.2F %.2F %.2F %.2F re %s ', $this->x * $k, ($this->h - $this->y) * $k, $w * $k, -$h * $k, $op); + } + if (is_string($border)) { + $x = $this->x; + $y = $this->y; + if (strpos($border, 'L') !== false) + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x * $k, ($this->h - $y) * $k, $x * $k, ($this->h - ($y + $h)) * $k); + if (strpos($border, 'T') !== false) + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - $y) * $k); + if (strpos($border, 'R') !== false) + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', ($x + $w) * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k); + if (strpos($border, 'B') !== false) + $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x * $k, ($this->h - ($y + $h)) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k); + } + $txt = (string)$txt; + if ($txt !== '') { + if (!isset($this->CurrentFont)) + $this->Error('No font has been set'); + if ($align == 'R') + $dx = $w - $this->cMargin - $this->GetStringWidth($txt); + elseif ($align == 'C') + $dx = ($w - $this->GetStringWidth($txt)) / 2; + else + $dx = $this->cMargin; + if ($this->ColorFlag) + $s .= 'q ' . $this->TextColor . ' '; + $s .= sprintf('BT %.2F %.2F Td (%s) Tj ET', ($this->x + $dx) * $k, ($this->h - ($this->y + .5 * $h + .3 * $this->FontSize)) * $k, $this->_escape($txt)); + if ($this->underline) + $s .= ' ' . $this->_dounderline($this->x + $dx, $this->y + .5 * $h + .3 * $this->FontSize, $txt); + if ($this->ColorFlag) + $s .= ' Q'; + if ($link) + $this->Link($this->x + $dx, $this->y + .5 * $h - .5 * $this->FontSize, $this->GetStringWidth($txt), $this->FontSize, $link); + } + if ($s) + $this->_out($s); + $this->lasth = $h; + if ($ln > 0) { + // Go to next line + $this->y += $h; + if ($ln == 1) + $this->x = $this->lMargin; + } else + $this->x += $w; + } + + function MultiCell($w, $h, $txt, $border = 0, $align = 'J', $fill = false) + { + // Output text with automatic or explicit line breaks + if (!isset($this->CurrentFont)) + $this->Error('No font has been set'); + $cw = $this->CurrentFont['cw']; + if ($w == 0) + $w = $this->w - $this->rMargin - $this->x; + $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; + $s = str_replace("\r", '', (string)$txt); + $nb = strlen($s); + if ($nb > 0 && $s[$nb - 1] == "\n") + $nb--; + $b = 0; + if ($border) { + if ($border == 1) { + $border = 'LTRB'; + $b = 'LRT'; + $b2 = 'LR'; + } else { + $b2 = ''; + if (strpos($border, 'L') !== false) + $b2 .= 'L'; + if (strpos($border, 'R') !== false) + $b2 .= 'R'; + $b = (strpos($border, 'T') !== false) ? $b2 . 'T' : $b2; + } + } + $sep = -1; + $i = 0; + $j = 0; + $l = 0; + $ns = 0; + $nl = 1; + while ($i < $nb) { + // Get next character + $c = $s[$i]; + if ($c == "\n") { + // Explicit line break + if ($this->ws > 0) { + $this->ws = 0; + $this->_out('0 Tw'); + } + $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill); + $i++; + $sep = -1; + $j = $i; + $l = 0; + $ns = 0; + $nl++; + if ($border && $nl == 2) + $b = $b2; + continue; + } + if ($c == ' ') { + $sep = $i; + $ls = $l; + $ns++; + } + $l += $cw[$c]; + if ($l > $wmax) { + // Automatic line break + if ($sep == -1) { + if ($i == $j) + $i++; + if ($this->ws > 0) { + $this->ws = 0; + $this->_out('0 Tw'); + } + $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill); + } else { + if ($align == 'J') { + $this->ws = ($ns > 1) ? ($wmax - $ls) / 1000 * $this->FontSize / ($ns - 1) : 0; + $this->_out(sprintf('%.3F Tw', $this->ws * $this->k)); + } + $this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill); + $i = $sep + 1; + } + $sep = -1; + $j = $i; + $l = 0; + $ns = 0; + $nl++; + if ($border && $nl == 2) + $b = $b2; + } else + $i++; + } + // Last chunk + if ($this->ws > 0) { + $this->ws = 0; + $this->_out('0 Tw'); + } + if ($border && strpos($border, 'B') !== false) + $b .= 'B'; + $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill); + $this->x = $this->lMargin; + } + + function Write($h, $txt, $link = '') + { + // Output text in flowing mode + if (!isset($this->CurrentFont)) + $this->Error('No font has been set'); + $cw = $this->CurrentFont['cw']; + $w = $this->w - $this->rMargin - $this->x; + $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; + $s = str_replace("\r", '', (string)$txt); + $nb = strlen($s); + $sep = -1; + $i = 0; + $j = 0; + $l = 0; + $nl = 1; + while ($i < $nb) { + // Get next character + $c = $s[$i]; + if ($c == "\n") { + // Explicit line break + $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', false, $link); + $i++; + $sep = -1; + $j = $i; + $l = 0; + if ($nl == 1) { + $this->x = $this->lMargin; + $w = $this->w - $this->rMargin - $this->x; + $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; + } + $nl++; + continue; + } + if ($c == ' ') + $sep = $i; + $l += $cw[$c]; + if ($l > $wmax) { + // Automatic line break + if ($sep == -1) { + if ($this->x > $this->lMargin) { + // Move to next line + $this->x = $this->lMargin; + $this->y += $h; + $w = $this->w - $this->rMargin - $this->x; + $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; + $i++; + $nl++; + continue; + } + if ($i == $j) + $i++; + $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', false, $link); + } else { + $this->Cell($w, $h, substr($s, $j, $sep - $j), 0, 2, '', false, $link); + $i = $sep + 1; + } + $sep = -1; + $j = $i; + $l = 0; + if ($nl == 1) { + $this->x = $this->lMargin; + $w = $this->w - $this->rMargin - $this->x; + $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize; + } + $nl++; + } else + $i++; + } + // Last chunk + if ($i != $j) + $this->Cell($l / 1000 * $this->FontSize, $h, substr($s, $j), 0, 0, '', false, $link); + } + + function Ln($h = null) + { + // Line feed; default value is the last cell height + $this->x = $this->lMargin; + if ($h === null) + $this->y += $this->lasth; + else + $this->y += $h; + } + + function Image($file, $x = null, $y = null, $w = 0, $h = 0, $type = '', $link = '') + { + // Put an image on the page + if ($file == '') + $this->Error('Image file name is empty'); + if (!isset($this->images[$file])) { + // First use of this image, get info + if ($type == '') { + $pos = strrpos($file, '.'); + if (!$pos) + $this->Error('Image file has no extension and no type was specified: ' . $file); + $type = substr($file, $pos + 1); + } + $type = strtolower($type); + if ($type == 'jpeg') + $type = 'jpg'; + $mtd = '_parse' . $type; + if (!method_exists($this, $mtd)) + $this->Error('Unsupported image type: ' . $type); + $info = $this->$mtd($file); + $info['i'] = count($this->images) + 1; + $this->images[$file] = $info; + } else + $info = $this->images[$file]; + + // Automatic width and height calculation if needed + if ($w == 0 && $h == 0) { + // Put image at 96 dpi + $w = -96; + $h = -96; + } + if ($w < 0) + $w = -$info['w'] * 72 / $w / $this->k; + if ($h < 0) + $h = -$info['h'] * 72 / $h / $this->k; + if ($w == 0) + $w = $h * $info['w'] / $info['h']; + if ($h == 0) + $h = $w * $info['h'] / $info['w']; + + // Flowing mode + if ($y === null) { + if ($this->y + $h > $this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak()) { + // Automatic page break + $x2 = $this->x; + $this->AddPage($this->CurOrientation, $this->CurPageSize, $this->CurRotation); + $this->x = $x2; + } + $y = $this->y; + $this->y += $h; + } + + if ($x === null) + $x = $this->x; + $this->_out(sprintf('q %.2F 0 0 %.2F %.2F %.2F cm /I%d Do Q', $w * $this->k, $h * $this->k, $x * $this->k, ($this->h - ($y + $h)) * $this->k, $info['i'])); + if ($link) + $this->Link($x, $y, $w, $h, $link); + } + + function GetPageWidth() + { + // Get current page width + return $this->w; + } + + function GetPageHeight() + { + // Get current page height + return $this->h; + } + + function GetX() + { + // Get x position + return $this->x; + } + + function SetX($x) + { + // Set x position + if ($x >= 0) + $this->x = $x; + else + $this->x = $this->w + $x; + } + + function GetY() + { + // Get y position + return $this->y; + } + + function SetY($y, $resetX = true) + { + // Set y position and optionally reset x + if ($y >= 0) + $this->y = $y; + else + $this->y = $this->h + $y; + if ($resetX) + $this->x = $this->lMargin; + } + + function SetXY($x, $y) + { + // Set x and y positions + $this->SetX($x); + $this->SetY($y, false); + } + + function Output($dest = '', $name = '', $isUTF8 = false) + { + // Output PDF to some destination + $this->Close(); + if (strlen($name) == 1 && strlen($dest) != 1) { + // Fix parameter order + $tmp = $dest; + $dest = $name; + $name = $tmp; + } + if ($dest == '') + $dest = 'I'; + if ($name == '') + $name = 'doc.pdf'; + switch (strtoupper($dest)) { + case 'I': + // Send to standard output + $this->_checkoutput(); + if (PHP_SAPI != 'cli') { + // We send to a browser + header('Content-Type: application/pdf'); + header('Content-Disposition: inline; ' . $this->_httpencode('filename', $name, $isUTF8)); + header('Cache-Control: private, max-age=0, must-revalidate'); + header('Pragma: public'); + } + echo $this->buffer; + break; + case 'D': + // Download file + $this->_checkoutput(); + header('Content-Type: application/pdf'); + header('Content-Disposition: attachment; ' . $this->_httpencode('filename', $name, $isUTF8)); + header('Cache-Control: private, max-age=0, must-revalidate'); + header('Pragma: public'); + echo $this->buffer; + break; + case 'F': + // Save to local file + if (!file_put_contents($name, $this->buffer)) + $this->Error('Unable to create output file: ' . $name); + break; + case 'S': + // Return as a string + return $this->buffer; + default: + $this->Error('Incorrect output destination: ' . $dest); + } + return ''; + } + + /******************************************************************************* + * Protected methods * + *******************************************************************************/ + + protected function _checkoutput() + { + if (PHP_SAPI != 'cli') { + if (headers_sent($file, $line)) + $this->Error("Some data has already been output, can't send PDF file (output started at $file:$line)"); + } + if (ob_get_length()) { + // The output buffer is not empty + if (preg_match('/^(\xEF\xBB\xBF)?\s*$/', ob_get_contents())) { + // It contains only a UTF-8 BOM and/or whitespace, let's clean it + ob_clean(); + } else + $this->Error("Some data has already been output, can't send PDF file"); + } + } + + protected function _getpagesize($size) + { + if (is_string($size)) { + $size = strtolower($size); + if (!isset($this->StdPageSizes[$size])) + $this->Error('Unknown page size: ' . $size); + $a = $this->StdPageSizes[$size]; + return array($a[0] / $this->k, $a[1] / $this->k); + } else { + if ($size[0] > $size[1]) + return array($size[1], $size[0]); + else + return $size; + } + } + + protected function _beginpage($orientation, $size, $rotation) + { + $this->page++; + $this->pages[$this->page] = ''; + $this->PageLinks[$this->page] = array(); + $this->state = 2; + $this->x = $this->lMargin; + $this->y = $this->tMargin; + $this->FontFamily = ''; + // Check page size and orientation + if ($orientation == '') + $orientation = $this->DefOrientation; + else + $orientation = strtoupper($orientation[0]); + if ($size == '') + $size = $this->DefPageSize; + else + $size = $this->_getpagesize($size); + if ($orientation != $this->CurOrientation || $size[0] != $this->CurPageSize[0] || $size[1] != $this->CurPageSize[1]) { + // New size or orientation + if ($orientation == 'P') { + $this->w = $size[0]; + $this->h = $size[1]; + } else { + $this->w = $size[1]; + $this->h = $size[0]; + } + $this->wPt = $this->w * $this->k; + $this->hPt = $this->h * $this->k; + $this->PageBreakTrigger = $this->h - $this->bMargin; + $this->CurOrientation = $orientation; + $this->CurPageSize = $size; + } + if ($orientation != $this->DefOrientation || $size[0] != $this->DefPageSize[0] || $size[1] != $this->DefPageSize[1]) + $this->PageInfo[$this->page]['size'] = array($this->wPt, $this->hPt); + if ($rotation != 0) { + if ($rotation % 90 != 0) + $this->Error('Incorrect rotation value: ' . $rotation); + $this->PageInfo[$this->page]['rotation'] = $rotation; + } + $this->CurRotation = $rotation; + } + + protected function _endpage() + { + $this->state = 1; + } + + protected function _loadfont($path) + { + // Load a font definition file + include($path); + if (!isset($name)) + $this->Error('Could not include font definition file: ' . $path); + if (isset($enc)) + $enc = strtolower($enc); + if (!isset($subsetted)) + $subsetted = false; + return get_defined_vars(); + } + + protected function _isascii($s) + { + // Test if string is ASCII + $nb = strlen($s); + for ($i = 0; $i < $nb; $i++) { + if (ord($s[$i]) > 127) + return false; + } + return true; + } + + protected function _httpencode($param, $value, $isUTF8) + { + // Encode HTTP header field parameter + if ($this->_isascii($value)) + return $param . '="' . $value . '"'; + if (!$isUTF8) + $value = $this->_UTF8encode($value); + return $param . "*=UTF-8''" . rawurlencode($value); + } + + protected function _UTF8encode($s) + { + // Convert ISO-8859-1 to UTF-8 + if ($this->iconv) + return iconv('ISO-8859-1', 'UTF-8', $s); + $res = ''; + $nb = strlen($s); + for ($i = 0; $i < $nb; $i++) { + $c = $s[$i]; + $v = ord($c); + if ($v >= 128) { + $res .= chr(0xC0 | ($v >> 6)); + $res .= chr(0x80 | ($v & 0x3F)); + } else + $res .= $c; + } + return $res; + } + + protected function _UTF8toUTF16($s) + { + // Convert UTF-8 to UTF-16BE with BOM + $res = "\xFE\xFF"; + if ($this->iconv) + return $res . iconv('UTF-8', 'UTF-16BE', $s); + $nb = strlen($s); + $i = 0; + while ($i < $nb) { + $c1 = ord($s[$i++]); + if ($c1 >= 224) { + // 3-byte character + $c2 = ord($s[$i++]); + $c3 = ord($s[$i++]); + $res .= chr((($c1 & 0x0F) << 4) + (($c2 & 0x3C) >> 2)); + $res .= chr((($c2 & 0x03) << 6) + ($c3 & 0x3F)); + } elseif ($c1 >= 192) { + // 2-byte character + $c2 = ord($s[$i++]); + $res .= chr(($c1 & 0x1C) >> 2); + $res .= chr((($c1 & 0x03) << 6) + ($c2 & 0x3F)); + } else { + // Single-byte character + $res .= "\0" . chr($c1); + } + } + return $res; + } + + protected function _escape($s) + { + // Escape special characters + if (strpos($s, '(') !== false || strpos($s, ')') !== false || strpos($s, '\\') !== false || strpos($s, "\r") !== false) + return str_replace(array('\\', '(', ')', "\r"), array('\\\\', '\\(', '\\)', '\\r'), $s); + else + return $s; + } + + protected function _textstring($s) + { + // Format a text string + if (!$this->_isascii($s)) + $s = $this->_UTF8toUTF16($s); + return '(' . $this->_escape($s) . ')'; + } + + protected function _dounderline($x, $y, $txt) + { + // Underline text + $up = $this->CurrentFont['up']; + $ut = $this->CurrentFont['ut']; + $w = $this->GetStringWidth($txt) + $this->ws * substr_count($txt, ' '); + return sprintf('%.2F %.2F %.2F %.2F re f', $x * $this->k, ($this->h - ($y - $up / 1000 * $this->FontSize)) * $this->k, $w * $this->k, -$ut / 1000 * $this->FontSizePt); + } + + protected function _parsejpg($file) + { + // Extract info from a JPEG file + $a = getimagesize($file); + if (!$a) + $this->Error('Missing or incorrect image file: ' . $file); + if ($a[2] != 2) + $this->Error('Not a JPEG file: ' . $file); + if (!isset($a['channels']) || $a['channels'] == 3) + $colspace = 'DeviceRGB'; + elseif ($a['channels'] == 4) + $colspace = 'DeviceCMYK'; + else + $colspace = 'DeviceGray'; + $bpc = isset($a['bits']) ? $a['bits'] : 8; + $data = file_get_contents($file); + return array('w' => $a[0], 'h' => $a[1], 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'DCTDecode', 'data' => $data); + } + + protected function _parsepng($file) + { + // Extract info from a PNG file + $f = fopen($file, 'rb'); + if (!$f) + $this->Error('Can\'t open image file: ' . $file); + $info = $this->_parsepngstream($f, $file); + fclose($f); + return $info; + } + + protected function _parsepngstream($f, $file) + { + // Check signature + if ($this->_readstream($f, 8) != chr(137) . 'PNG' . chr(13) . chr(10) . chr(26) . chr(10)) + $this->Error('Not a PNG file: ' . $file); + + // Read header chunk + $this->_readstream($f, 4); + if ($this->_readstream($f, 4) != 'IHDR') + $this->Error('Incorrect PNG file: ' . $file); + $w = $this->_readint($f); + $h = $this->_readint($f); + $bpc = ord($this->_readstream($f, 1)); + if ($bpc > 8) + $this->Error('16-bit depth not supported: ' . $file); + $ct = ord($this->_readstream($f, 1)); + if ($ct == 0 || $ct == 4) + $colspace = 'DeviceGray'; + elseif ($ct == 2 || $ct == 6) + $colspace = 'DeviceRGB'; + elseif ($ct == 3) + $colspace = 'Indexed'; + else + $this->Error('Unknown color type: ' . $file); + if (ord($this->_readstream($f, 1)) != 0) + $this->Error('Unknown compression method: ' . $file); + if (ord($this->_readstream($f, 1)) != 0) + $this->Error('Unknown filter method: ' . $file); + if (ord($this->_readstream($f, 1)) != 0) + $this->Error('Interlacing not supported: ' . $file); + $this->_readstream($f, 4); + $dp = '/Predictor 15 /Colors ' . ($colspace == 'DeviceRGB' ? 3 : 1) . ' /BitsPerComponent ' . $bpc . ' /Columns ' . $w; + + // Scan chunks looking for palette, transparency and image data + $pal = ''; + $trns = ''; + $data = ''; + do { + $n = $this->_readint($f); + $type = $this->_readstream($f, 4); + if ($type == 'PLTE') { + // Read palette + $pal = $this->_readstream($f, $n); + $this->_readstream($f, 4); + } elseif ($type == 'tRNS') { + // Read transparency info + $t = $this->_readstream($f, $n); + if ($ct == 0) + $trns = array(ord(substr($t, 1, 1))); + elseif ($ct == 2) + $trns = array(ord(substr($t, 1, 1)), ord(substr($t, 3, 1)), ord(substr($t, 5, 1))); + else { + $pos = strpos($t, chr(0)); + if ($pos !== false) + $trns = array($pos); + } + $this->_readstream($f, 4); + } elseif ($type == 'IDAT') { + // Read image data block + $data .= $this->_readstream($f, $n); + $this->_readstream($f, 4); + } elseif ($type == 'IEND') + break; + else + $this->_readstream($f, $n + 4); + } while ($n); + + if ($colspace == 'Indexed' && empty($pal)) + $this->Error('Missing palette in ' . $file); + $info = array('w' => $w, 'h' => $h, 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'FlateDecode', 'dp' => $dp, 'pal' => $pal, 'trns' => $trns); + if ($ct >= 4) { + // Extract alpha channel + if (!function_exists('gzuncompress')) + $this->Error('Zlib not available, can\'t handle alpha channel: ' . $file); + $data = gzuncompress($data); + $color = ''; + $alpha = ''; + if ($ct == 4) { + // Gray image + $len = 2 * $w; + for ($i = 0; $i < $h; $i++) { + $pos = (1 + $len) * $i; + $color .= $data[$pos]; + $alpha .= $data[$pos]; + $line = substr($data, $pos + 1, $len); + $color .= preg_replace('/(.)./s', '$1', $line); + $alpha .= preg_replace('/.(.)/s', '$1', $line); + } + } else { + // RGB image + $len = 4 * $w; + for ($i = 0; $i < $h; $i++) { + $pos = (1 + $len) * $i; + $color .= $data[$pos]; + $alpha .= $data[$pos]; + $line = substr($data, $pos + 1, $len); + $color .= preg_replace('/(.{3})./s', '$1', $line); + $alpha .= preg_replace('/.{3}(.)/s', '$1', $line); + } + } + unset($data); + $data = gzcompress($color); + $info['smask'] = gzcompress($alpha); + $this->WithAlpha = true; + if ($this->PDFVersion < '1.4') + $this->PDFVersion = '1.4'; + } + $info['data'] = $data; + return $info; + } + + protected function _readstream($f, $n) + { + // Read n bytes from stream + $res = ''; + while ($n > 0 && !feof($f)) { + $s = fread($f, $n); + if ($s === false) + $this->Error('Error while reading stream'); + $n -= strlen($s); + $res .= $s; + } + if ($n > 0) + $this->Error('Unexpected end of stream'); + return $res; + } + + protected function _readint($f) + { + // Read a 4-byte integer from stream + $a = unpack('Ni', $this->_readstream($f, 4)); + return $a['i']; + } + + protected function _parsegif($file) + { + // Extract info from a GIF file (via PNG conversion) + if (!function_exists('imagepng')) + $this->Error('GD extension is required for GIF support'); + if (!function_exists('imagecreatefromgif')) + $this->Error('GD has no GIF read support'); + $im = imagecreatefromgif($file); + if (!$im) + $this->Error('Missing or incorrect image file: ' . $file); + imageinterlace($im, 0); + ob_start(); + imagepng($im); + $data = ob_get_clean(); + imagedestroy($im); + $f = fopen('php://temp', 'rb+'); + if (!$f) + $this->Error('Unable to create memory stream'); + fwrite($f, $data); + rewind($f); + $info = $this->_parsepngstream($f, $file); + fclose($f); + return $info; + } + + protected function _out($s) + { + // Add a line to the current page + if ($this->state == 2) + $this->pages[$this->page] .= $s . "\n"; + elseif ($this->state == 0) + $this->Error('No page has been added yet'); + elseif ($this->state == 1) + $this->Error('Invalid call'); + elseif ($this->state == 3) + $this->Error('The document is closed'); + } + + protected function _put($s) + { + // Add a line to the document + $this->buffer .= $s . "\n"; + } + + protected function _getoffset() + { + return strlen($this->buffer); + } + + protected function _newobj($n = null) + { + // Begin a new object + if ($n === null) + $n = ++$this->n; + $this->offsets[$n] = $this->_getoffset(); + $this->_put($n . ' 0 obj'); + } + + protected function _putstream($data) + { + $this->_put('stream'); + $this->_put($data); + $this->_put('endstream'); + } + + protected function _putstreamobject($data) + { + if ($this->compress) { + $entries = '/Filter /FlateDecode '; + $data = gzcompress($data); + } else + $entries = ''; + $entries .= '/Length ' . strlen($data); + $this->_newobj(); + $this->_put('<<' . $entries . '>>'); + $this->_putstream($data); + $this->_put('endobj'); + } + + protected function _putlinks($n) + { + foreach ($this->PageLinks[$n] as $pl) { + $this->_newobj(); + $rect = sprintf('%.2F %.2F %.2F %.2F', $pl[0], $pl[1], $pl[0] + $pl[2], $pl[1] - $pl[3]); + $s = '<_textstring($pl[4]) . '>>>>'; + else { + $l = $this->links[$pl[4]]; + if (isset($this->PageInfo[$l[0]]['size'])) + $h = $this->PageInfo[$l[0]]['size'][1]; + else + $h = ($this->DefOrientation == 'P') ? $this->DefPageSize[1] * $this->k : $this->DefPageSize[0] * $this->k; + $s .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>', $this->PageInfo[$l[0]]['n'], $h - $l[1] * $this->k); + } + $this->_put($s); + $this->_put('endobj'); + } + } + + protected function _putpage($n) + { + $this->_newobj(); + $this->_put('<_put('/Parent 1 0 R'); + if (isset($this->PageInfo[$n]['size'])) + $this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]', $this->PageInfo[$n]['size'][0], $this->PageInfo[$n]['size'][1])); + if (isset($this->PageInfo[$n]['rotation'])) + $this->_put('/Rotate ' . $this->PageInfo[$n]['rotation']); + $this->_put('/Resources 2 0 R'); + if (!empty($this->PageLinks[$n])) { + $s = '/Annots ['; + foreach ($this->PageLinks[$n] as $pl) + $s .= $pl[5] . ' 0 R '; + $s .= ']'; + $this->_put($s); + } + if ($this->WithAlpha) + $this->_put('/Group <>'); + $this->_put('/Contents ' . ($this->n + 1) . ' 0 R>>'); + $this->_put('endobj'); + // Page content + if (!empty($this->AliasNbPages)) + $this->pages[$n] = str_replace($this->AliasNbPages, $this->page, $this->pages[$n]); + $this->_putstreamobject($this->pages[$n]); + // Link annotations + $this->_putlinks($n); + } + + protected function _putpages() + { + $nb = $this->page; + $n = $this->n; + for ($i = 1; $i <= $nb; $i++) { + $this->PageInfo[$i]['n'] = ++$n; + $n++; + foreach ($this->PageLinks[$i] as &$pl) + $pl[5] = ++$n; + unset($pl); + } + for ($i = 1; $i <= $nb; $i++) + $this->_putpage($i); + // Pages root + $this->_newobj(1); + $this->_put('<PageInfo[$i]['n'] . ' 0 R '; + $kids .= ']'; + $this->_put($kids); + $this->_put('/Count ' . $nb); + if ($this->DefOrientation == 'P') { + $w = $this->DefPageSize[0]; + $h = $this->DefPageSize[1]; + } else { + $w = $this->DefPageSize[1]; + $h = $this->DefPageSize[0]; + } + $this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]', $w * $this->k, $h * $this->k)); + $this->_put('>>'); + $this->_put('endobj'); + } + + protected function _putfonts() + { + foreach ($this->FontFiles as $file => $info) { + // Font file embedding + $this->_newobj(); + $this->FontFiles[$file]['n'] = $this->n; + $font = file_get_contents($file); + if (!$font) + $this->Error('Font file not found: ' . $file); + $compressed = (substr($file, -2) == '.z'); + if (!$compressed && isset($info['length2'])) + $font = substr($font, 6, $info['length1']) . substr($font, 6 + $info['length1'] + 6, $info['length2']); + $this->_put('<_put('/Filter /FlateDecode'); + $this->_put('/Length1 ' . $info['length1']); + if (isset($info['length2'])) + $this->_put('/Length2 ' . $info['length2'] . ' /Length3 0'); + $this->_put('>>'); + $this->_putstream($font); + $this->_put('endobj'); + } + foreach ($this->fonts as $k => $font) { + // Encoding + if (isset($font['diff'])) { + if (!isset($this->encodings[$font['enc']])) { + $this->_newobj(); + $this->_put('<>'); + $this->_put('endobj'); + $this->encodings[$font['enc']] = $this->n; + } + } + // ToUnicode CMap + if (isset($font['uv'])) { + if (isset($font['enc'])) + $cmapkey = $font['enc']; + else + $cmapkey = $font['name']; + if (!isset($this->cmaps[$cmapkey])) { + $cmap = $this->_tounicodecmap($font['uv']); + $this->_putstreamobject($cmap); + $this->cmaps[$cmapkey] = $this->n; + } + } + // Font object + $this->fonts[$k]['n'] = $this->n + 1; + $type = $font['type']; + $name = $font['name']; + if ($font['subsetted']) + $name = 'AAAAAA+' . $name; + if ($type == 'Core') { + // Core font + $this->_newobj(); + $this->_put('<_put('/BaseFont /' . $name); + $this->_put('/Subtype /Type1'); + if ($name != 'Symbol' && $name != 'ZapfDingbats') + $this->_put('/Encoding /WinAnsiEncoding'); + if (isset($font['uv'])) + $this->_put('/ToUnicode ' . $this->cmaps[$cmapkey] . ' 0 R'); + $this->_put('>>'); + $this->_put('endobj'); + } elseif ($type == 'Type1' || $type == 'TrueType') { + // Additional Type1 or TrueType/OpenType font + $this->_newobj(); + $this->_put('<_put('/BaseFont /' . $name); + $this->_put('/Subtype /' . $type); + $this->_put('/FirstChar 32 /LastChar 255'); + $this->_put('/Widths ' . ($this->n + 1) . ' 0 R'); + $this->_put('/FontDescriptor ' . ($this->n + 2) . ' 0 R'); + if (isset($font['diff'])) + $this->_put('/Encoding ' . $this->encodings[$font['enc']] . ' 0 R'); + else + $this->_put('/Encoding /WinAnsiEncoding'); + if (isset($font['uv'])) + $this->_put('/ToUnicode ' . $this->cmaps[$cmapkey] . ' 0 R'); + $this->_put('>>'); + $this->_put('endobj'); + // Widths + $this->_newobj(); + $cw = $font['cw']; + $s = '['; + for ($i = 32; $i <= 255; $i++) + $s .= $cw[chr($i)] . ' '; + $this->_put($s . ']'); + $this->_put('endobj'); + // Descriptor + $this->_newobj(); + $s = '< $v) + $s .= ' /' . $k . ' ' . $v; + if (!empty($font['file'])) + $s .= ' /FontFile' . ($type == 'Type1' ? '' : '2') . ' ' . $this->FontFiles[$font['file']]['n'] . ' 0 R'; + $this->_put($s . '>>'); + $this->_put('endobj'); + } else { + // Allow for additional types + $mtd = '_put' . strtolower($type); + if (!method_exists($this, $mtd)) + $this->Error('Unsupported font type: ' . $type); + $this->$mtd($font); + } + } + } + + protected function _tounicodecmap($uv) + { + $ranges = ''; + $nbr = 0; + $chars = ''; + $nbc = 0; + foreach ($uv as $c => $v) { + if (is_array($v)) { + $ranges .= sprintf("<%02X> <%02X> <%04X>\n", $c, $c + $v[1] - 1, $v[0]); + $nbr++; + } else { + $chars .= sprintf("<%02X> <%04X>\n", $c, $v); + $nbc++; + } + } + $s = "/CIDInit /ProcSet findresource begin\n"; + $s .= "12 dict begin\n"; + $s .= "begincmap\n"; + $s .= "/CIDSystemInfo\n"; + $s .= "< 0) { + $s .= "$nbr beginbfrange\n"; + $s .= $ranges; + $s .= "endbfrange\n"; + } + if ($nbc > 0) { + $s .= "$nbc beginbfchar\n"; + $s .= $chars; + $s .= "endbfchar\n"; + } + $s .= "endcmap\n"; + $s .= "CMapName currentdict /CMap defineresource pop\n"; + $s .= "end\n"; + $s .= "end"; + return $s; + } + + protected function _putimages() + { + foreach (array_keys($this->images) as $file) { + $this->_putimage($this->images[$file]); + unset($this->images[$file]['data']); + unset($this->images[$file]['smask']); + } + } + + protected function _putimage(&$info) + { + $this->_newobj(); + $info['n'] = $this->n; + $this->_put('<_put('/Subtype /Image'); + $this->_put('/Width ' . $info['w']); + $this->_put('/Height ' . $info['h']); + if ($info['cs'] == 'Indexed') + $this->_put('/ColorSpace [/Indexed /DeviceRGB ' . (strlen($info['pal']) / 3 - 1) . ' ' . ($this->n + 1) . ' 0 R]'); + else { + $this->_put('/ColorSpace /' . $info['cs']); + if ($info['cs'] == 'DeviceCMYK') + $this->_put('/Decode [1 0 1 0 1 0 1 0]'); + } + $this->_put('/BitsPerComponent ' . $info['bpc']); + if (isset($info['f'])) + $this->_put('/Filter /' . $info['f']); + if (isset($info['dp'])) + $this->_put('/DecodeParms <<' . $info['dp'] . '>>'); + if (isset($info['trns']) && is_array($info['trns'])) { + $trns = ''; + for ($i = 0; $i < count($info['trns']); $i++) + $trns .= $info['trns'][$i] . ' ' . $info['trns'][$i] . ' '; + $this->_put('/Mask [' . $trns . ']'); + } + if (isset($info['smask'])) + $this->_put('/SMask ' . ($this->n + 1) . ' 0 R'); + $this->_put('/Length ' . strlen($info['data']) . '>>'); + $this->_putstream($info['data']); + $this->_put('endobj'); + // Soft mask + if (isset($info['smask'])) { + $dp = '/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns ' . $info['w']; + $smask = array('w' => $info['w'], 'h' => $info['h'], 'cs' => 'DeviceGray', 'bpc' => 8, 'f' => $info['f'], 'dp' => $dp, 'data' => $info['smask']); + $this->_putimage($smask); + } + // Palette + if ($info['cs'] == 'Indexed') + $this->_putstreamobject($info['pal']); + } + + protected function _putxobjectdict() + { + foreach ($this->images as $image) + $this->_put('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R'); + } + + protected function _putresourcedict() + { + $this->_put('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); + $this->_put('/Font <<'); + foreach ($this->fonts as $font) + $this->_put('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R'); + $this->_put('>>'); + $this->_put('/XObject <<'); + $this->_putxobjectdict(); + $this->_put('>>'); + } + + protected function _putresources() + { + $this->_putfonts(); + $this->_putimages(); + // Resource dictionary + $this->_newobj(2); + $this->_put('<<'); + $this->_putresourcedict(); + $this->_put('>>'); + $this->_put('endobj'); + } + + protected function _putinfo() + { + $date = @date('YmdHisO', $this->CreationDate); + $this->metadata['CreationDate'] = 'D:' . substr($date, 0, -2) . "'" . substr($date, -2) . "'"; + foreach ($this->metadata as $key => $value) + $this->_put('/' . $key . ' ' . $this->_textstring($value)); + } + + protected function _putcatalog() + { + $n = $this->PageInfo[1]['n']; + $this->_put('/Type /Catalog'); + $this->_put('/Pages 1 0 R'); + if ($this->ZoomMode == 'fullpage') + $this->_put('/OpenAction [' . $n . ' 0 R /Fit]'); + elseif ($this->ZoomMode == 'fullwidth') + $this->_put('/OpenAction [' . $n . ' 0 R /FitH null]'); + elseif ($this->ZoomMode == 'real') + $this->_put('/OpenAction [' . $n . ' 0 R /XYZ null null 1]'); + elseif (!is_string($this->ZoomMode)) + $this->_put('/OpenAction [' . $n . ' 0 R /XYZ null null ' . sprintf('%.2F', $this->ZoomMode / 100) . ']'); + if ($this->LayoutMode == 'single') + $this->_put('/PageLayout /SinglePage'); + elseif ($this->LayoutMode == 'continuous') + $this->_put('/PageLayout /OneColumn'); + elseif ($this->LayoutMode == 'two') + $this->_put('/PageLayout /TwoColumnLeft'); + } + + protected function _putheader() + { + $this->_put('%PDF-' . $this->PDFVersion); + } + + protected function _puttrailer() + { + $this->_put('/Size ' . ($this->n + 1)); + $this->_put('/Root ' . $this->n . ' 0 R'); + $this->_put('/Info ' . ($this->n - 1) . ' 0 R'); + } + + protected function _enddoc() + { + $this->CreationDate = time(); + $this->_putheader(); + $this->_putpages(); + $this->_putresources(); + // Info + $this->_newobj(); + $this->_put('<<'); + $this->_putinfo(); + $this->_put('>>'); + $this->_put('endobj'); + // Catalog + $this->_newobj(); + $this->_put('<<'); + $this->_putcatalog(); + $this->_put('>>'); + $this->_put('endobj'); + // Cross-ref + $offset = $this->_getoffset(); + $this->_put('xref'); + $this->_put('0 ' . ($this->n + 1)); + $this->_put('0000000000 65535 f '); + for ($i = 1; $i <= $this->n; $i++) + $this->_put(sprintf('%010d 00000 n ', $this->offsets[$i])); + // Trailer + $this->_put('trailer'); + $this->_put('<<'); + $this->_puttrailer(); + $this->_put('>>'); + $this->_put('startxref'); + $this->_put($offset); + $this->_put('%%EOF'); + $this->state = 3; + } +} \ No newline at end of file diff --git a/bootstrap/app.php b/bootstrap/app.php index 0b4f4ca5..4f387ec5 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -1,27 +1,11 @@ withRouting( @@ -31,39 +15,39 @@ return Application::configure(basePath: dirname(__DIR__)) health: '/up', ) ->withMiddleware(function (Middleware $middleware): void { - $middleware->append(SecurityHeaders::class); + $middleware->append(\App\Http\Middleware\SecurityHeaders::class); $middleware->alias([ // JWT auth - 'jwt.auth' => Authenticate::class, - 'jwt.refresh' => RefreshToken::class, - 'api.jwt' => ApiJwtAuth::class, + 'jwt.auth' => \PHPOpenSourceSaver\JWTAuth\Http\Middleware\Authenticate::class, + 'jwt.refresh' => \PHPOpenSourceSaver\JWTAuth\Http\Middleware\RefreshToken::class, + 'api.jwt' => \App\Http\Middleware\ApiJwtAuth::class, // Multi-guard auth (both the new and legacy alias point at the same class) - 'auth.multi' => MultiAuth::class, - 'multi.auth' => MultiAuth::class, + 'auth.multi' => \App\Http\Middleware\MultiAuth::class, + 'multi.auth' => \App\Http\Middleware\MultiAuth::class, // Permission / role gates - 'perm' => RequirePermission::class, - 'require.permission' => RequirePermission::class, - 'admin.access' => EnsurePrintRequestsAdminAccess::class, - 'parent.access' => EnsureParentProgressAccess::class, - 'parent.progress' => EnsureParentProgressAccess::class, - 'teacher.progress' => EnsureClassProgressTeacherPortalAccess::class, - 'class_progress.teacher' => EnsureClassProgressTeacherPortalAccess::class, - 'school_year.editable' => EnsureSchoolYearEditable::class, - 'print_requests.teacher' => EnsurePrintRequestsTeacherAccess::class, - 'print_requests.admin' => EnsurePrintRequestsAdminAccess::class, - 'badge_scan.logs' => EnsureBadgeScanLogsAccess::class, + 'perm' => \App\Http\Middleware\RequirePermission::class, + 'require.permission' => \App\Http\Middleware\RequirePermission::class, + 'admin.access' => \App\Http\Middleware\EnsurePrintRequestsAdminAccess::class, + 'parent.access' => \App\Http\Middleware\EnsureParentProgressAccess::class, + 'parent.progress' => \App\Http\Middleware\EnsureParentProgressAccess::class, + 'teacher.progress' => \App\Http\Middleware\EnsureClassProgressTeacherPortalAccess::class, + 'class_progress.teacher' => \App\Http\Middleware\EnsureClassProgressTeacherPortalAccess::class, + 'school_year.editable' => \App\Http\Middleware\EnsureSchoolYearEditable::class, + 'print_requests.teacher' => \App\Http\Middleware\EnsurePrintRequestsTeacherAccess::class, + 'print_requests.admin' => \App\Http\Middleware\EnsurePrintRequestsAdminAccess::class, + 'badge_scan.logs' => \App\Http\Middleware\EnsureBadgeScanLogsAccess::class, // Docs + teacher portal - 'auth.docs' => ApiDocsAuth::class, - 'teacher.portal.auth' => TeacherPortalAuthenticate::class, + 'auth.docs' => \App\Http\Middleware\ApiDocsAuth::class, + 'teacher.portal.auth' => \App\Http\Middleware\TeacherPortalAuthenticate::class, // Utility - 'timezone' => PrimeTimezone::class, - 'prime.timezone' => PrimeTimezone::class, - 'cleanup.scheduler' => CleanupScheduler::class, + 'timezone' => \App\Http\Middleware\PrimeTimezone::class, + 'prime.timezone' => \App\Http\Middleware\PrimeTimezone::class, + 'cleanup.scheduler' => \App\Http\Middleware\CleanupScheduler::class, ]); $middleware->redirectGuestsTo(function (Request $request) { diff --git a/bootstrap/providers.php b/bootstrap/providers.php index 78c06f72..86f5297a 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -1,9 +1,6 @@ [ 'users' => [ 'driver' => 'eloquent', - 'model' => env('AUTH_MODEL', User::class), + 'model' => env('AUTH_MODEL', App\Models\User::class), ], // 'users' => [ diff --git a/config/jwt.php b/config/jwt.php index 50871625..d131f6e4 100644 --- a/config/jwt.php +++ b/config/jwt.php @@ -1,8 +1,5 @@ Lcobucci::class, + 'jwt' => PHPOpenSourceSaver\JWTAuth\Providers\JWT\Lcobucci::class, /* |-------------------------------------------------------------------------- @@ -309,7 +306,7 @@ return [ | */ - 'auth' => Illuminate::class, + 'auth' => PHPOpenSourceSaver\JWTAuth\Providers\Auth\Illuminate::class, /* |-------------------------------------------------------------------------- diff --git a/config/sanctum.php b/config/sanctum.php index cde73cff..44527d68 100644 --- a/config/sanctum.php +++ b/config/sanctum.php @@ -1,8 +1,5 @@ [ - 'authenticate_session' => AuthenticateSession::class, - 'encrypt_cookies' => EncryptCookies::class, - 'validate_csrf_token' => ValidateCsrfToken::class, + 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, + 'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class, + 'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, ], ]; diff --git a/database/factories/ClassSectionFactory.php b/database/factories/ClassSectionFactory.php index da024b77..69a733bd 100644 --- a/database/factories/ClassSectionFactory.php +++ b/database/factories/ClassSectionFactory.php @@ -6,7 +6,7 @@ use App\Models\ClassSection; use Illuminate\Database\Eloquent\Factories\Factory; /** - * @extends Factory + * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\ClassSection> */ class ClassSectionFactory extends Factory { @@ -19,7 +19,7 @@ class ClassSectionFactory extends Factory return [ 'class_id' => fake()->numberBetween(1, 20), 'class_section_id' => $sectionId, - 'class_section_name' => (string) $sectionId.fake()->randomElement(['A', 'B', 'C']), + 'class_section_name' => (string) $sectionId . fake()->randomElement(['A', 'B', 'C']), 'semester' => 'Fall', 'school_year' => '2025-2026', ]; diff --git a/database/factories/StudentFactory.php b/database/factories/StudentFactory.php index 4bd700bd..e50def9f 100644 --- a/database/factories/StudentFactory.php +++ b/database/factories/StudentFactory.php @@ -6,7 +6,7 @@ use App\Models\Student; use Illuminate\Database\Eloquent\Factories\Factory; /** - * @extends Factory + * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Student> */ class StudentFactory extends Factory { @@ -15,13 +15,13 @@ class StudentFactory extends Factory public function definition(): array { return [ - 'school_id' => 'S-'.fake()->numberBetween(100, 999), + 'school_id' => 'S-' . fake()->numberBetween(100, 999), 'firstname' => fake()->firstName(), 'lastname' => fake()->lastName(), 'age' => fake()->numberBetween(6, 18), 'gender' => fake()->randomElement(['Male', 'Female']), 'is_active' => 1, - 'registration_grade' => 'Grade '.fake()->numberBetween(1, 8), + 'registration_grade' => 'Grade ' . fake()->numberBetween(1, 8), 'is_new' => 1, 'photo_consent' => 1, 'parent_id' => fake()->numberBetween(1, 50), diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 6da14826..5212a445 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -2,12 +2,12 @@ namespace Database\Factories; -use App\Models\User; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Str; /** - * @extends Factory + * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User> */ class UserFactory extends Factory { diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php index e3adbe14..eaafe5d6 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -1,6 +1,7 @@ string('email')->nullable()->after('name'); } - if (! Schema::hasColumn('suppliers', 'phone')) { + if (!Schema::hasColumn('suppliers', 'phone')) { $table->string('phone')->nullable()->after('email'); } - if (! Schema::hasColumn('suppliers', 'address')) { + if (!Schema::hasColumn('suppliers', 'address')) { $table->string('address')->nullable()->after('phone'); } - if (! Schema::hasColumn('suppliers', 'notes')) { + if (!Schema::hasColumn('suppliers', 'notes')) { $table->text('notes')->nullable()->after('address'); } }); diff --git a/database/migrations/2026_06_04_120000_create_certificate_records_table.php b/database/migrations/2026_06_04_120000_create_certificate_records_table.php index 4da26ef1..a5593ded 100644 --- a/database/migrations/2026_06_04_120000_create_certificate_records_table.php +++ b/database/migrations/2026_06_04_120000_create_certificate_records_table.php @@ -1,6 +1,5 @@ string('lifecycle_mode', 20)->default('legacy'); } - if (! Schema::hasColumn($table, 'lifecycle_policy_version')) { + if (!Schema::hasColumn($table, 'lifecycle_policy_version')) { $t->string('lifecycle_policy_version', 30)->default('legacy_v1'); } }); } - if (! Schema::hasTable('section_placement_batches')) { + if (!Schema::hasTable('section_placement_batches')) { Schema::create('section_placement_batches', function (Blueprint $table) { $table->id(); $table->string('from_school_year', 25); @@ -45,7 +45,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('section_placement_batch_students')) { + if (!Schema::hasTable('section_placement_batch_students')) { Schema::create('section_placement_batch_students', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('batch_id'); @@ -70,7 +70,7 @@ return new class extends Migration if (Schema::hasTable('configuration')) { $exists = DB::table('configuration')->where('config_key', 'promotion.section_capacity')->exists(); - if (! $exists) { + if (!$exists) { DB::table('configuration')->insert([ 'config_key' => 'promotion.section_capacity', 'config_value' => '20', diff --git a/database/migrations/2026_06_04_200000_add_badge_scanning_list_nav_item.php b/database/migrations/2026_06_04_200000_add_badge_scanning_list_nav_item.php index 3cdcbf0c..458d827b 100644 --- a/database/migrations/2026_06_04_200000_add_badge_scanning_list_nav_item.php +++ b/database/migrations/2026_06_04_200000_add_badge_scanning_list_nav_item.php @@ -8,7 +8,7 @@ return new class extends Migration { public function up(): void { - if (! Schema::hasTable('nav_items') || ! Schema::hasTable('role_nav_items') || ! Schema::hasTable('roles')) { + if (!Schema::hasTable('nav_items') || !Schema::hasTable('role_nav_items') || !Schema::hasTable('roles')) { return; } @@ -26,7 +26,7 @@ return new class extends Migration ->where('url', $url) ->value('id'); - if (! $navId) { + if (!$navId) { $navId = DB::table('nav_items')->insertGetId([ 'menu_parent_id' => $parentId ?: null, 'label' => $label, @@ -70,7 +70,7 @@ return new class extends Migration ->where('nav_item_id', $navId) ->exists(); - if (! $exists) { + if (!$exists) { DB::table('role_nav_items')->insert([ 'role_id' => $roleId, 'nav_item_id' => $navId, @@ -83,7 +83,7 @@ return new class extends Migration public function down(): void { - if (! Schema::hasTable('nav_items')) { + if (!Schema::hasTable('nav_items')) { return; } diff --git a/database/migrations/2026_06_04_210000_add_strong_grading_backward_compatibility.php b/database/migrations/2026_06_04_210000_add_strong_grading_backward_compatibility.php index 639e67f3..f54c8795 100644 --- a/database/migrations/2026_06_04_210000_add_strong_grading_backward_compatibility.php +++ b/database/migrations/2026_06_04_210000_add_strong_grading_backward_compatibility.php @@ -10,24 +10,24 @@ return new class extends Migration public function up(): void { foreach (['homework', 'quiz', 'project', 'participation', 'midterm_exam', 'final_exam'] as $table) { - if (! Schema::hasTable($table)) { + if (!Schema::hasTable($table)) { continue; } Schema::table($table, function (Blueprint $tableBlueprint) use ($table) { - if (! Schema::hasColumn($table, 'max_points')) { + if (!Schema::hasColumn($table, 'max_points')) { $tableBlueprint->decimal('max_points', 8, 2)->default(100)->after('score'); } - if (! Schema::hasColumn($table, 'status')) { + if (!Schema::hasColumn($table, 'status')) { $tableBlueprint->string('status', 30)->nullable()->after('max_points'); } - if (! Schema::hasColumn($table, 'excused_reason')) { + if (!Schema::hasColumn($table, 'excused_reason')) { $tableBlueprint->text('excused_reason')->nullable()->after('status'); } - if (! Schema::hasColumn($table, 'locked_at')) { + if (!Schema::hasColumn($table, 'locked_at')) { $tableBlueprint->timestamp('locked_at')->nullable()->after('excused_reason'); } - if (! Schema::hasColumn($table, 'locked_by')) { + if (!Schema::hasColumn($table, 'locked_by')) { $tableBlueprint->unsignedBigInteger('locked_by')->nullable()->after('locked_at'); } }); @@ -41,13 +41,13 @@ return new class extends Migration if (Schema::hasTable('semester_scores')) { Schema::table('semester_scores', function (Blueprint $table) { - if (! Schema::hasColumn('semester_scores', 'calculation_mode')) { + if (!Schema::hasColumn('semester_scores', 'calculation_mode')) { $table->string('calculation_mode', 30)->default('legacy')->after('semester_score'); } - if (! Schema::hasColumn('semester_scores', 'calculation_policy_version')) { + if (!Schema::hasColumn('semester_scores', 'calculation_policy_version')) { $table->string('calculation_policy_version', 50)->default('legacy_v1')->after('calculation_mode'); } - if (! Schema::hasColumn('semester_scores', 'snapshot_id')) { + if (!Schema::hasColumn('semester_scores', 'snapshot_id')) { $table->unsignedBigInteger('snapshot_id')->nullable()->after('calculation_policy_version'); } }); @@ -56,7 +56,7 @@ return new class extends Migration DB::table('semester_scores')->whereNull('calculation_policy_version')->update(['calculation_policy_version' => 'legacy_v1']); } - if (! Schema::hasTable('semester_score_snapshots')) { + if (!Schema::hasTable('semester_score_snapshots')) { Schema::create('semester_score_snapshots', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('student_id'); @@ -96,7 +96,7 @@ return new class extends Migration } foreach (['homework', 'quiz', 'project', 'participation', 'midterm_exam', 'final_exam'] as $tableName) { - if (! Schema::hasTable($tableName)) { + if (!Schema::hasTable($tableName)) { continue; } Schema::table($tableName, function (Blueprint $table) use ($tableName) { diff --git a/database/migrations/2026_06_04_230000_add_finance_lifecycle_tables.php b/database/migrations/2026_06_04_230000_add_finance_lifecycle_tables.php index 140c4e7f..9bb7c9eb 100644 --- a/database/migrations/2026_06_04_230000_add_finance_lifecycle_tables.php +++ b/database/migrations/2026_06_04_230000_add_finance_lifecycle_tables.php @@ -8,7 +8,7 @@ return new class extends Migration { public function up(): void { - if (! Schema::hasTable('finance_follow_up_notes')) { + if (!Schema::hasTable('finance_follow_up_notes')) { Schema::create('finance_follow_up_notes', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('parent_id')->index(); @@ -26,7 +26,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('finance_balance_carryforwards')) { + if (!Schema::hasTable('finance_balance_carryforwards')) { Schema::create('finance_balance_carryforwards', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('parent_id')->index(); @@ -52,7 +52,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('invoice_installment_plans')) { + if (!Schema::hasTable('invoice_installment_plans')) { Schema::create('invoice_installment_plans', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('invoice_id')->index(); @@ -68,7 +68,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('invoice_installments')) { + if (!Schema::hasTable('invoice_installments')) { Schema::create('invoice_installments', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('installment_plan_id')->index(); @@ -85,7 +85,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('payment_installment_allocations')) { + if (!Schema::hasTable('payment_installment_allocations')) { Schema::create('payment_installment_allocations', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('payment_id')->index(); @@ -96,7 +96,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('finance_notification_logs')) { + if (!Schema::hasTable('finance_notification_logs')) { Schema::create('finance_notification_logs', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('parent_id')->nullable()->index(); @@ -119,7 +119,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('finance_notification_preferences')) { + if (!Schema::hasTable('finance_notification_preferences')) { Schema::create('finance_notification_preferences', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('parent_id')->unique(); @@ -132,7 +132,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('finance_receipt_sequences')) { + if (!Schema::hasTable('finance_receipt_sequences')) { Schema::create('finance_receipt_sequences', function (Blueprint $table) { $table->id(); $table->string('school_year')->unique(); @@ -142,7 +142,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('payment_carryforward_allocations')) { + if (!Schema::hasTable('payment_carryforward_allocations')) { Schema::create('payment_carryforward_allocations', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('payment_id')->index(); diff --git a/database/migrations/2026_06_05_000000_create_school_year_closure_tables.php b/database/migrations/2026_06_05_000000_create_school_year_closure_tables.php index 6206ba38..5c0a638a 100644 --- a/database/migrations/2026_06_05_000000_create_school_year_closure_tables.php +++ b/database/migrations/2026_06_05_000000_create_school_year_closure_tables.php @@ -9,7 +9,7 @@ return new class extends Migration { public function up(): void { - if (! Schema::hasTable('school_years')) { + if (!Schema::hasTable('school_years')) { Schema::create('school_years', function (Blueprint $table) { $table->id(); $table->string('name', 50)->unique(); @@ -23,7 +23,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('parent_accounts')) { + if (!Schema::hasTable('parent_accounts')) { Schema::create('parent_accounts', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('parent_id')->index(); @@ -35,7 +35,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('parent_balance_transfers')) { + if (!Schema::hasTable('parent_balance_transfers')) { Schema::create('parent_balance_transfers', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('parent_id')->index(); @@ -51,7 +51,7 @@ return new class extends Migration }); } - if (! Schema::hasTable('audit_logs')) { + if (!Schema::hasTable('audit_logs')) { Schema::create('audit_logs', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('user_id')->nullable()->index(); @@ -65,7 +65,7 @@ return new class extends Migration }); } - if (Schema::hasTable('invoices') && ! Schema::hasColumn('invoices', 'balance_transfer_id')) { + if (Schema::hasTable('invoices') && !Schema::hasColumn('invoices', 'balance_transfer_id')) { Schema::table('invoices', function (Blueprint $table) { $table->unsignedBigInteger('balance_transfer_id')->nullable()->index()->after('semester'); }); @@ -90,7 +90,7 @@ return new class extends Migration private function seedCurrentSchoolYear(): void { - if (! Schema::hasTable('configuration') || ! Schema::hasTable('school_years')) { + if (!Schema::hasTable('configuration') || !Schema::hasTable('school_years')) { return; } @@ -111,7 +111,6 @@ return new class extends Migration 'is_current' => true, 'updated_at' => now(), ]); - return; } diff --git a/database/migrations/2026_06_05_000000_sort_nav_items_alphabetically.php b/database/migrations/2026_06_05_000000_sort_nav_items_alphabetically.php index 505dd65a..4672ca80 100644 --- a/database/migrations/2026_06_05_000000_sort_nav_items_alphabetically.php +++ b/database/migrations/2026_06_05_000000_sort_nav_items_alphabetically.php @@ -8,7 +8,7 @@ return new class extends Migration { public function up(): void { - if (! Schema::hasTable('nav_items')) { + if (!Schema::hasTable('nav_items')) { return; } diff --git a/database/migrations/2026_06_09_000000_create_stats_table.php b/database/migrations/2026_06_09_000000_create_stats_table.php new file mode 100644 index 00000000..4feb509b --- /dev/null +++ b/database/migrations/2026_06_09_000000_create_stats_table.php @@ -0,0 +1,29 @@ +id(); + $table->unsignedInteger('students')->default(0); + $table->unsignedInteger('teachers')->default(0); + $table->unsignedInteger('admins')->default(0); + $table->unsignedInteger('users')->default(0); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('stats'); + } +}; diff --git a/docs/alrahma_end_to_end_use_case_test_plan.md b/docs/alrahma_end_to_end_use_case_test_plan.md index 38957ada..f0642972 100644 --- a/docs/alrahma_end_to_end_use_case_test_plan.md +++ b/docs/alrahma_end_to_end_use_case_test_plan.md @@ -2585,3 +2585,21 @@ New coverage areas: - Batch 20 continuity/compliance risk register and regression sweep. This batch is meant to catch the quiet business-rule failures: the payment that balances only because the client said so, the grade changed after lock, the export that includes medical notes, the badge scan that trusts a header, and the emergency broadcast that ignores consent. Tiny details, enormous blast radius. + +## Batch 20 CI Failure Remediation Patch + +This patch addresses the first GitLab failures observed after the Batch 20 full-surface suite started executing in CI. + +Applied fixes: + +- Switched GitLab PHPUnit execution from SQLite to a MySQL service so MySQL-specific production queries such as `GROUP_CONCAT(... ORDER BY ... SEPARATOR ...)` run against the same SQL dialect they were written for. +- Updated `phpunit.xml` DB defaults to MySQL for CI parity and replaced the invalid APP_KEY with a valid AES-256-CBC testing key. +- Hardened `POST /api/v1/students` validation so required non-null database fields fail with 422 instead of falling through to database constraint errors. +- Split student creation payloads from first-child emergency-contact payloads so parent/contact fields are no longer sent into `Student::create()`. +- Added a `stats` table migration and guarded stats controllers so stats endpoints do not 500 in empty/test databases. +- Normalized refund overpayment invoice rows with `toArray()` and defensive ID checks to remove `Undefined array key "id"` failures. +- Made manual payment record/edit failures return controlled 4xx responses instead of bubbling domain exceptions into 5xx responses. +- Tightened full-surface student payload generation so student probes include required fields such as age, photo consent, registration year, and activation flags. +- Documented intentional legacy/unversioned compatibility routes in the versioning contract allow-list. + +The goal of this remediation is not to weaken the broad test net. It removes environmental mismatches and real application crashes so the next CI run exposes the next layer of actual behavior failures. diff --git a/gitlab-ci.yml b/gitlab-ci.yml index a15d0b76..30a5d519 100644 --- a/gitlab-ci.yml +++ b/gitlab-ci.yml @@ -20,8 +20,16 @@ variables: APP_ENV: testing APP_DEBUG: "false" LOG_CHANNEL: stderr - DB_CONNECTION: sqlite - DB_DATABASE: "$CI_PROJECT_DIR/database/database.sqlite" + DB_CONNECTION: mysql + DB_HOST: mysql + DB_PORT: "3306" + DB_DATABASE: school_api_test + DB_USERNAME: school_api + DB_PASSWORD: school_api + MYSQL_DATABASE: school_api_test + MYSQL_USER: school_api + MYSQL_PASSWORD: school_api + MYSQL_ROOT_PASSWORD: root CACHE_DRIVER: array CACHE_STORE: array SESSION_DRIVER: array @@ -43,10 +51,13 @@ cache: phpunit: image: php:8.3-cli stage: test + services: + - name: mysql:8.4 + alias: mysql before_script: - apt-get update - - apt-get install -y --no-install-recommends git unzip curl libzip-dev libpng-dev libonig-dev libxml2-dev libsqlite3-dev libcurl4-openssl-dev - - docker-php-ext-install curl dom gd mbstring pdo pdo_sqlite xml xmlwriter zip + - apt-get install -y --no-install-recommends git unzip curl default-mysql-client libzip-dev libpng-dev libonig-dev libxml2-dev libcurl4-openssl-dev + - docker-php-ext-install curl dom gd mbstring pdo pdo_mysql xml xmlwriter zip - php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" - php composer-setup.php --install-dir=/usr/local/bin --filename=composer - rm composer-setup.php @@ -60,8 +71,12 @@ phpunit: APP_URL=http://localhost LOG_CHANNEL=stderr LOG_LEVEL=debug - DB_CONNECTION=sqlite - DB_DATABASE=$CI_PROJECT_DIR/database/database.sqlite + DB_CONNECTION=mysql + DB_HOST=mysql + DB_PORT=3306 + DB_DATABASE=school_api_test + DB_USERNAME=school_api + DB_PASSWORD=school_api CACHE_DRIVER=array CACHE_STORE=array SESSION_DRIVER=array @@ -72,7 +87,11 @@ phpunit: JWT_SECRET=ci_dummy_secret_not_for_production EOF - mkdir -p database storage/framework/cache storage/framework/sessions storage/framework/views storage/logs bootstrap/cache reports - - touch database/database.sqlite + - | + until mysqladmin ping -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USERNAME" -p"$DB_PASSWORD" --silent; do + echo "Waiting for MySQL..." + sleep 2 + done - php artisan key:generate --force - php artisan config:clear - php artisan migrate --force diff --git a/phpunit.xml b/phpunit.xml index fbcd5e9d..78474888 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -19,15 +19,19 @@ - + - - + + + + + + diff --git a/routes/api.php b/routes/api.php index 8204d4c2..bd22a180 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,130 +1,137 @@ middleware('throttle:10,1'); Route::post('register', [RegisterController::class, 'store'])->middleware('throttle:5,1'); @@ -605,8 +612,8 @@ Route::prefix('v1')->group(function () { Route::get('teacher/select-semester', function () { return response()->json([ 'ok' => true, - 'school_year' => Configuration::getConfig('school_year'), - 'semester' => Configuration::getConfig('semester'), + 'school_year' => \App\Models\Configuration::getConfig('school_year'), + 'semester' => \App\Models\Configuration::getConfig('semester'), 'semester_options' => ['Fall', 'Spring'], ]); }); @@ -980,7 +987,7 @@ Route::prefix('v1')->group(function () { Route::post('event-charges/{eventCharge}/void', [EventChargeController::class, 'void'])->whereNumber('eventCharge'); Route::post('event-charges/{eventCharge}/attach-to-invoice', [EventChargeController::class, 'attachToInvoice'])->whereNumber('eventCharge'); - Route::apiResource('installment-plans', InstallmentPlanController::class)->only(['index', 'show']); + Route::apiResource('installment-plans', InstallmentPlanController::class)->only(['index','show']); Route::post('invoices/{invoice}/installment-plans', [InstallmentPlanController::class, 'store'])->whereNumber('invoice'); Route::post('installment-plans/{plan}/activate', [InstallmentPlanController::class, 'activate'])->whereNumber('plan'); Route::post('installment-plans/{plan}/cancel', [InstallmentPlanController::class, 'cancel'])->whereNumber('plan'); diff --git a/tests/Concerns/AssertsE2EApiResponses.php b/tests/Concerns/AssertsE2EApiResponses.php index b42eb071..c9b754cc 100644 --- a/tests/Concerns/AssertsE2EApiResponses.php +++ b/tests/Concerns/AssertsE2EApiResponses.php @@ -11,19 +11,19 @@ trait AssertsE2EApiResponses $this->assertLessThan( 500, $response->getStatusCode(), - $context.' should return a controlled response, not a 5xx crash. Body: '.$response->getContent() + $context . ' should return a controlled response, not a 5xx crash. Body: ' . $response->getContent() ); } /** - * @param array $statuses + * @param array $statuses */ protected function assertStatusIn(TestResponse $response, array $statuses, string $context): void { $this->assertContains( $response->getStatusCode(), $statuses, - $context.' returned unexpected status '.$response->getStatusCode().'. Body: '.$response->getContent() + $context . ' returned unexpected status ' . $response->getStatusCode() . '. Body: ' . $response->getContent() ); } diff --git a/tests/Concerns/CreatesApiTestUsers.php b/tests/Concerns/CreatesApiTestUsers.php index 0d7a1ea2..5f22084b 100644 --- a/tests/Concerns/CreatesApiTestUsers.php +++ b/tests/Concerns/CreatesApiTestUsers.php @@ -68,7 +68,7 @@ trait CreatesApiTestUsers 'status' => 'Active', 'is_verified' => 1, 'is_suspended' => 0, - 'email' => $roleName.'-api-test-'.str_replace('.', '', uniqid('', true)).'@example.test', + 'email' => $roleName . '-api-test-' . str_replace('.', '', uniqid('', true)) . '@example.test', ], $overrides)); $role = $roles[$roleName] ?? Role::query()->where('name', $roleName)->firstOrFail(); diff --git a/tests/Concerns/SeedsAdministratorApiConfig.php b/tests/Concerns/SeedsAdministratorApiConfig.php index d1f8e010..9eac17ad 100644 --- a/tests/Concerns/SeedsAdministratorApiConfig.php +++ b/tests/Concerns/SeedsAdministratorApiConfig.php @@ -22,4 +22,4 @@ trait SeedsAdministratorApiConfig ['config_value' => $semester] ); } -} +} \ No newline at end of file diff --git a/tests/Concerns/SeedsE2ETestFixtures.php b/tests/Concerns/SeedsE2ETestFixtures.php index 59bda107..d3376cb6 100644 --- a/tests/Concerns/SeedsE2ETestFixtures.php +++ b/tests/Concerns/SeedsE2ETestFixtures.php @@ -18,9 +18,7 @@ trait SeedsE2ETestFixtures use CreatesApiTestUsers; protected const E2E_SCHOOL_YEAR = '2025-2026'; - protected const E2E_PREV_SCHOOL_YEAR = '2024-2025'; - protected const E2E_SEMESTER = 'Fall'; protected function seedE2EConfiguration(): void @@ -110,18 +108,18 @@ trait SeedsE2ETestFixtures $teacher = $this->createApiUserWithRole('teacher', [ 'firstname' => 'Tara', 'lastname' => 'Teacher', - 'email' => 'e2e.teacher.'.uniqid('', true).'@example.test', + 'email' => 'e2e.teacher.' . uniqid('', true) . '@example.test', ]); $this->seedTeacherClassAssignment($teacher->id, $classSectionId); $parent = $this->createApiUserWithRole('parent', [ 'firstname' => 'Parent', 'lastname' => 'Fixture', - 'email' => 'e2e.parent.'.uniqid('', true).'@example.test', + 'email' => 'e2e.parent.' . uniqid('', true) . '@example.test', ]); $studentId = DB::table('students')->insertGetId([ - 'school_id' => 'S-E2E-'.random_int(1000, 9999), + 'school_id' => 'S-E2E-' . random_int(1000, 9999), 'firstname' => 'Kai', 'lastname' => 'Student', 'dob' => '2014-09-01', @@ -223,7 +221,7 @@ trait SeedsE2ETestFixtures protected function postEnrollmentStatuses(array $studentStatusMap): TestResponse { return $this->post( - '/api/v1/administrator/enrollment-withdrawal/update-statuses?'. + '/api/v1/administrator/enrollment-withdrawal/update-statuses?' . http_build_query(['enrollment_status' => $studentStatusMap]), [] ); @@ -233,7 +231,7 @@ trait SeedsE2ETestFixtures { return DB::table('invoices')->insertGetId(array_merge([ 'parent_id' => $parentId, - 'invoice_number' => 'INV-E2E-'.random_int(1000, 9999), + 'invoice_number' => 'INV-E2E-' . random_int(1000, 9999), 'total_amount' => 500.00, 'balance' => 500.00, 'paid_amount' => 0, @@ -252,7 +250,7 @@ trait SeedsE2ETestFixtures { return DB::table('invoices')->insertGetId([ 'parent_id' => $parentId, - 'invoice_number' => 'INV-PRIOR-'.random_int(1000, 9999), + 'invoice_number' => 'INV-PRIOR-' . random_int(1000, 9999), 'total_amount' => 200.00, 'balance' => 150.00, 'paid_amount' => 50.00, @@ -270,7 +268,7 @@ trait SeedsE2ETestFixtures protected function seedDiscountVoucher(): int { return DB::table('discount_vouchers')->insertGetId([ - 'code' => 'E2E10-'.random_int(100, 999), + 'code' => 'E2E10-' . random_int(100, 999), 'discount_type' => 'fixed', 'discount_value' => 50, 'max_uses' => 100, diff --git a/tests/Feature/Api/ApiAuthenticationAndAuthorizationTest.php b/tests/Feature/Api/ApiAuthenticationAndAuthorizationTest.php index edff0530..ebe6a27a 100644 --- a/tests/Feature/Api/ApiAuthenticationAndAuthorizationTest.php +++ b/tests/Feature/Api/ApiAuthenticationAndAuthorizationTest.php @@ -13,6 +13,7 @@ class ApiAuthenticationAndAuthorizationTest extends TestCase use CreatesApiTestUsers; use RefreshDatabase; + public function test_api_login_returns_token_and_user_object(): void { $user = $this->createApiUserWithRole('teacher', [ @@ -102,7 +103,7 @@ class ApiAuthenticationAndAuthorizationTest extends TestCase foreach ($this->sampleProtectedRoutes() as $route) { $method = $this->primaryMethod($route); - $uri = '/'.$this->uriWithPlaceholders($route->uri()); + $uri = '/' . $this->uriWithPlaceholders($route->uri()); $response = $this->json($method, $uri); $status = $response->getStatusCode(); @@ -112,7 +113,7 @@ class ApiAuthenticationAndAuthorizationTest extends TestCase } } - $this->assertSame([], $failures, "Anonymous requests reached unexpected responses:\n".implode("\n", $failures)); + $this->assertSame([], $failures, "Anonymous requests reached unexpected responses:\n" . implode("\n", $failures)); } /** diff --git a/tests/Feature/Api/ApiPreferencesFeatureTest.php b/tests/Feature/Api/ApiPreferencesFeatureTest.php index 041058e2..b01d52e4 100644 --- a/tests/Feature/Api/ApiPreferencesFeatureTest.php +++ b/tests/Feature/Api/ApiPreferencesFeatureTest.php @@ -47,6 +47,7 @@ class ApiPreferencesFeatureTest extends TestCase ->assertJsonPath('status', true); } + public function test_non_admin_cannot_list_or_manage_another_users_preferences(): void { $owner = $this->createApiUserWithRole('teacher'); diff --git a/tests/Feature/Api/ApiPublicEndpointsTest.php b/tests/Feature/Api/ApiPublicEndpointsTest.php index 7b78015f..990670a7 100644 --- a/tests/Feature/Api/ApiPublicEndpointsTest.php +++ b/tests/Feature/Api/ApiPublicEndpointsTest.php @@ -36,7 +36,7 @@ class ApiPublicEndpointsTest extends TestCase public function test_public_frontend_content_endpoints_do_not_server_error(): void { foreach (['/', 'facility', 'team', 'call-to-action', 'testimonial', 'not-found'] as $path) { - $uri = '/api/v1/frontend'.($path === '/' ? '' : '/'.$path); + $uri = '/api/v1/frontend' . ($path === '/' ? '' : '/' . $path); $response = $this->getJson($uri); $this->assertLessThan(500, $response->getStatusCode(), "$uri returned a server error"); diff --git a/tests/Feature/Api/ApiRolePermissionFeatureTest.php b/tests/Feature/Api/ApiRolePermissionFeatureTest.php index de0c6dc1..99e6d6a8 100644 --- a/tests/Feature/Api/ApiRolePermissionFeatureTest.php +++ b/tests/Feature/Api/ApiRolePermissionFeatureTest.php @@ -2,6 +2,8 @@ namespace Tests\Feature\Api; +use App\Models\Permission; +use App\Models\Role; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\Concerns\CreatesApiTestUsers; diff --git a/tests/Feature/Api/ApiRouteContractTest.php b/tests/Feature/Api/ApiRouteContractTest.php index 70a87260..35df3ec7 100644 --- a/tests/Feature/Api/ApiRouteContractTest.php +++ b/tests/Feature/Api/ApiRouteContractTest.php @@ -24,11 +24,11 @@ class ApiRouteContractTest extends TestCase [$class, $method] = explode('@', $action, 2); if (! class_exists($class) || ! method_exists($class, $method)) { - $missing[] = implode('|', $route->methods()).' '.$route->uri().' -> '.$action; + $missing[] = implode('|', $route->methods()) . ' ' . $route->uri() . ' -> ' . $action; } } - $this->assertSame([], $missing, "These API routes reference missing controllers or methods:\n".implode("\n", $missing)); + $this->assertSame([], $missing, "These API routes reference missing controllers or methods:\n" . implode("\n", $missing)); } public function test_api_routes_do_not_duplicate_method_and_uri_pairs(): void @@ -42,7 +42,7 @@ class ApiRouteContractTest extends TestCase continue; } - $key = $method.' '.$route->uri(); + $key = $method . ' ' . $route->uri(); if (isset($seen[$key])) { $duplicates[] = $key; } @@ -90,11 +90,11 @@ class ApiRouteContractTest extends TestCase }); if (! $hasProtection) { - $unprotected[] = implode('|', $methods).' '.$route->uri(); + $unprotected[] = implode('|', $methods) . ' ' . $route->uri(); } } - $this->assertSame([], $unprotected, "Mutating API routes without an obvious auth/throttle middleware:\n".implode("\n", $unprotected)); + $this->assertSame([], $unprotected, "Mutating API routes without an obvious auth/throttle middleware:\n" . implode("\n", $unprotected)); } /** diff --git a/tests/Feature/Api/ApiUseCaseCoverageMatrixTest.php b/tests/Feature/Api/ApiUseCaseCoverageMatrixTest.php index 23b97766..84812b97 100644 --- a/tests/Feature/Api/ApiUseCaseCoverageMatrixTest.php +++ b/tests/Feature/Api/ApiUseCaseCoverageMatrixTest.php @@ -26,14 +26,14 @@ class ApiUseCaseCoverageMatrixTest extends TestCase $uri = $route->uri(); if ($this->domainFor($uri) === null) { - $unmapped[] = implode('|', array_diff($route->methods(), ['HEAD'])).' '.$uri; + $unmapped[] = implode('|', array_diff($route->methods(), ['HEAD'])) . ' ' . $uri; } } $this->assertSame( [], $unmapped, - "API routes without an explicit use-case domain:\n".implode("\n", $unmapped). + "API routes without an explicit use-case domain:\n" . implode("\n", $unmapped) . "\n\nAdd the route to the matrix and then add/extend an E2E workflow test for that domain." ); } @@ -53,7 +53,7 @@ class ApiUseCaseCoverageMatrixTest extends TestCase $this->assertSame( [], $missing, - "Required use-case domains with no matching API route coverage:\n".implode("\n", $missing) + "Required use-case domains with no matching API route coverage:\n" . implode("\n", $missing) ); } @@ -63,7 +63,7 @@ class ApiUseCaseCoverageMatrixTest extends TestCase foreach ($this->protectedRoutes() as $route) { $method = $this->primaryMethod($route); - $uri = '/'.$this->uriWithSafePlaceholders($route->uri()); + $uri = '/' . $this->uriWithSafePlaceholders($route->uri()); $response = $this->json($method, $uri); $status = $response->getStatusCode(); @@ -76,7 +76,7 @@ class ApiUseCaseCoverageMatrixTest extends TestCase $this->assertSame( [], $failures, - "Anonymous requests reached protected API routes unexpectedly:\n".implode("\n", $failures) + "Anonymous requests reached protected API routes unexpectedly:\n" . implode("\n", $failures) ); } diff --git a/tests/Feature/Api/ApiUserManagementFeatureTest.php b/tests/Feature/Api/ApiUserManagementFeatureTest.php index 5c352464..20058411 100644 --- a/tests/Feature/Api/ApiUserManagementFeatureTest.php +++ b/tests/Feature/Api/ApiUserManagementFeatureTest.php @@ -2,6 +2,7 @@ namespace Tests\Feature\Api; +use App\Models\Role; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Hash; diff --git a/tests/Feature/Api/V1/Administrator/AdministratorAbsenceControllerTest.php b/tests/Feature/Api/V1/Administrator/AdministratorAbsenceControllerTest.php index 203c6b48..cc354eab 100644 --- a/tests/Feature/Api/V1/Administrator/AdministratorAbsenceControllerTest.php +++ b/tests/Feature/Api/V1/Administrator/AdministratorAbsenceControllerTest.php @@ -121,4 +121,4 @@ class AdministratorAbsenceControllerTest extends TestCase 'dates' => ['2026-03-08'], ]); } -} +} \ No newline at end of file diff --git a/tests/Feature/Api/V1/Administrator/AdministratorEnrollmentControllerTest.php b/tests/Feature/Api/V1/Administrator/AdministratorEnrollmentControllerTest.php index 06c5daee..85c81f08 100644 --- a/tests/Feature/Api/V1/Administrator/AdministratorEnrollmentControllerTest.php +++ b/tests/Feature/Api/V1/Administrator/AdministratorEnrollmentControllerTest.php @@ -128,4 +128,4 @@ class AdministratorEnrollmentControllerTest extends TestCase 'message' => 'Enrollment statuses updated and notifications sent.', ]); } -} +} \ No newline at end of file diff --git a/tests/Feature/Api/V1/Administrator/AdministratorEnrollmentUpdateStatusesApiTest.php b/tests/Feature/Api/V1/Administrator/AdministratorEnrollmentUpdateStatusesApiTest.php index 41e287ce..15744d66 100644 --- a/tests/Feature/Api/V1/Administrator/AdministratorEnrollmentUpdateStatusesApiTest.php +++ b/tests/Feature/Api/V1/Administrator/AdministratorEnrollmentUpdateStatusesApiTest.php @@ -263,7 +263,6 @@ class AdministratorEnrollmentUpdateStatusesApiTest extends TestCase private function postUpdateStatuses(array $enrollmentStatus) { $query = http_build_query(['enrollment_status' => $enrollmentStatus]); - - return $this->post('/api/v1/administrator/enrollment-withdrawal/update-statuses?'.$query, []); + return $this->post('/api/v1/administrator/enrollment-withdrawal/update-statuses?' . $query, []); } } diff --git a/tests/Feature/Api/V1/Administrator/AdministratorNotificationControllerTest.php b/tests/Feature/Api/V1/Administrator/AdministratorNotificationControllerTest.php index 3b7dae6b..136c57e6 100644 --- a/tests/Feature/Api/V1/Administrator/AdministratorNotificationControllerTest.php +++ b/tests/Feature/Api/V1/Administrator/AdministratorNotificationControllerTest.php @@ -157,4 +157,4 @@ class AdministratorNotificationControllerTest extends TestCase 'message' => 'Print notification recipients updated.', ]); } -} +} \ No newline at end of file diff --git a/tests/Feature/Api/V1/Administrator/AdministratorTeacherSubmissionControllerTest.php b/tests/Feature/Api/V1/Administrator/AdministratorTeacherSubmissionControllerTest.php index 9ca1e12b..26020d38 100644 --- a/tests/Feature/Api/V1/Administrator/AdministratorTeacherSubmissionControllerTest.php +++ b/tests/Feature/Api/V1/Administrator/AdministratorTeacherSubmissionControllerTest.php @@ -2,10 +2,10 @@ namespace Tests\Feature\Api\Administrator; -use App\Http\Middleware\EnsurePrintRequestsAdminAccess; use App\Models\User; use App\Services\Administrator\TeacherSubmissionNotificationService; use App\Services\Administrator\TeacherSubmissionReportService; +use App\Http\Middleware\EnsurePrintRequestsAdminAccess; use Illuminate\Foundation\Testing\RefreshDatabase; use Laravel\Sanctum\Sanctum; use Mockery; diff --git a/tests/Feature/Api/V1/Administrator/AdministratorTeacherSubmissionReportApiTest.php b/tests/Feature/Api/V1/Administrator/AdministratorTeacherSubmissionReportApiTest.php index 8aae8e46..7aae2821 100644 --- a/tests/Feature/Api/V1/Administrator/AdministratorTeacherSubmissionReportApiTest.php +++ b/tests/Feature/Api/V1/Administrator/AdministratorTeacherSubmissionReportApiTest.php @@ -281,7 +281,7 @@ class AdministratorTeacherSubmissionReportApiTest extends TestCase 'class_section_id' => 12, 'admin_id' => 901, 'notification_category' => 'teacher_submissions', - 'message' => 'Reminder '.$i, + 'message' => 'Reminder ' . $i, 'status' => 'sent', 'school_year' => '2025-2026', 'semester' => 'Fall', diff --git a/tests/Feature/Api/V1/Administrator/EmergencyContactControllerTest.php b/tests/Feature/Api/V1/Administrator/EmergencyContactControllerTest.php index 4ecd47f4..6da928a2 100644 --- a/tests/Feature/Api/V1/Administrator/EmergencyContactControllerTest.php +++ b/tests/Feature/Api/V1/Administrator/EmergencyContactControllerTest.php @@ -80,7 +80,7 @@ class EmergencyContactControllerTest extends TestCase ]); Sanctum::actingAs($admin, [], 'api'); - $response = $this->patch('/api/v1/administrator/emergency-contacts/'.$contact->id, [ + $response = $this->patch('/api/v1/administrator/emergency-contacts/' . $contact->id, [ 'parent_id' => $parent->id, 'name' => 'New Name', 'cellphone' => '5555555555', @@ -116,7 +116,7 @@ class EmergencyContactControllerTest extends TestCase ]); Sanctum::actingAs($admin, [], 'api'); - $response = $this->delete('/api/v1/administrator/emergency-contacts/'.$contact->id, [ + $response = $this->delete('/api/v1/administrator/emergency-contacts/' . $contact->id, [ 'parent_id' => $parent->id, ], [ 'Accept' => 'application/json', @@ -145,7 +145,7 @@ class EmergencyContactControllerTest extends TestCase ]); Sanctum::actingAs($admin, [], 'api'); - $response = $this->get('/api/v1/administrator/emergency-contacts/'.$contact->id.'?parent_id='.$parent->id, [ + $response = $this->get('/api/v1/administrator/emergency-contacts/' . $contact->id . '?parent_id=' . $parent->id, [ 'Accept' => 'application/json', ]); @@ -171,7 +171,7 @@ class EmergencyContactControllerTest extends TestCase ]); Sanctum::actingAs($admin, [], 'api'); - $response = $this->patch('/api/v1/administrator/emergency-contacts/'.$contact->id, [ + $response = $this->patch('/api/v1/administrator/emergency-contacts/' . $contact->id, [ 'parent_id' => $otherParent->id, 'name' => 'New Name', 'cellphone' => '9999999999', @@ -205,7 +205,7 @@ class EmergencyContactControllerTest extends TestCase ]); Sanctum::actingAs($admin, [], 'api'); - $response = $this->delete('/api/v1/administrator/emergency-contacts/'.$contact->id, [ + $response = $this->delete('/api/v1/administrator/emergency-contacts/' . $contact->id, [ 'parent_id' => $otherParent->id, ], [ 'Accept' => 'application/json', diff --git a/tests/Feature/Api/V1/Assignment/AssignmentApiControllerTest.php b/tests/Feature/Api/V1/Assignment/AssignmentApiControllerTest.php index 1ee1b586..3a37da73 100644 --- a/tests/Feature/Api/V1/Assignment/AssignmentApiControllerTest.php +++ b/tests/Feature/Api/V1/Assignment/AssignmentApiControllerTest.php @@ -16,17 +16,11 @@ class AssignmentApiControllerTest extends TestCase use RefreshDatabase; protected User $user; - protected User $teacherMain; - protected User $teacherAssistant; - protected ClassSection $sectionA; - protected ClassSection $sectionB; - protected Student $studentOne; - protected Student $studentTwo; protected function setUp(): void @@ -424,4 +418,4 @@ class AssignmentApiControllerTest extends TestCase $this->assertSame(['Main Teacher'], $mainTeachers); } -} +} \ No newline at end of file diff --git a/tests/Feature/Api/V1/AssignmentApiTest.php b/tests/Feature/Api/V1/AssignmentApiTest.php index 64c3f6a1..c66523d4 100644 --- a/tests/Feature/Api/V1/AssignmentApiTest.php +++ b/tests/Feature/Api/V1/AssignmentApiTest.php @@ -2,12 +2,12 @@ namespace Tests\Feature\Api; -use App\Models\ClassSection; -use App\Models\Configuration; +use App\Models\User; use App\Models\Student; use App\Models\StudentClass; use App\Models\TeacherClass; -use App\Models\User; +use App\Models\ClassSection; +use App\Models\Configuration; use Illuminate\Foundation\Testing\RefreshDatabase; use Laravel\Sanctum\Sanctum; use PHPUnit\Framework\Attributes\Test; @@ -48,36 +48,36 @@ class AssignmentApiTest extends TestCase $teacher = User::factory()->create([ 'firstname' => 'Ahmad', - 'lastname' => 'Ali', + 'lastname' => 'Ali', ]); TeacherClass::query()->create([ - 'teacher_id' => $teacher->id, - 'class_section_id' => $section->class_section_id, - 'position' => 'main', - 'semester' => 'Fall', - 'school_year' => '2025-2026', - 'description' => 'Main teacher assignment', + 'teacher_id' => $teacher->id, + 'class_section_id' => $section->class_section_id, + 'position' => 'main', + 'semester' => 'Fall', + 'school_year' => '2025-2026', + 'description' => 'Main teacher assignment', ]); $student = Student::factory()->create([ - 'firstname' => 'Sara', - 'lastname' => 'Yousef', - 'is_active' => 1, - 'gender' => 'F', + 'firstname' => 'Sara', + 'lastname' => 'Yousef', + 'is_active' => 1, + 'gender' => 'F', 'registration_grade' => '5', - 'photo_consent' => 1, - 'tuition_paid' => 1, - 'school_id' => 'SCH-1001', + 'photo_consent' => 1, + 'tuition_paid' => 1, + 'school_id' => 'SCH-1001', ]); StudentClass::query()->create([ - 'student_id' => $student->id, - 'class_section_id' => $section->class_section_id, - 'semester' => 'Fall', - 'school_year' => '2025-2026', - 'description' => 'Student assigned', - 'is_active' => 1, // remove if your table doesn’t have this column + 'student_id' => $student->id, + 'class_section_id' => $section->class_section_id, + 'semester' => 'Fall', + 'school_year' => '2025-2026', + 'description' => 'Student assigned', + 'is_active' => 1, // remove if your table doesn’t have this column ]); $response = $this->getJson('/api/assignments'); @@ -96,7 +96,7 @@ class AssignmentApiTest extends TestCase 'semester', 'school_year', 'description', - ], + ] ], 'schoolYears', 'selectedYear', @@ -122,19 +122,19 @@ class AssignmentApiTest extends TestCase $teacher = User::factory()->create(['firstname' => 'Test', 'lastname' => 'Teacher']); TeacherClass::query()->create([ - 'teacher_id' => $teacher->id, + 'teacher_id' => $teacher->id, 'class_section_id' => $section1->class_section_id, - 'position' => 'main', - 'semester' => 'Fall', - 'school_year' => '2024-2025', + 'position' => 'main', + 'semester' => 'Fall', + 'school_year' => '2024-2025', ]); TeacherClass::query()->create([ - 'teacher_id' => $teacher->id, + 'teacher_id' => $teacher->id, 'class_section_id' => $section2->class_section_id, - 'position' => 'main', - 'semester' => 'Fall', - 'school_year' => '2025-2026', + 'position' => 'main', + 'semester' => 'Fall', + 'school_year' => '2025-2026', ]); $response = $this->getJson('/api/assignments?school_year=2025-2026'); @@ -158,11 +158,11 @@ class AssignmentApiTest extends TestCase $section = ClassSection::factory()->create(); $payload = [ - 'student_id' => $student->id, + 'student_id' => $student->id, 'class_section_id' => $section->class_section_id, - 'semester' => 'Spring', - 'school_year' => '2025-2026', - 'description' => 'Moved after placement review', + 'semester' => 'Spring', + 'school_year' => '2025-2026', + 'description' => 'Moved after placement review', ]; $response = $this->postJson('/api/assignments', $payload); @@ -171,10 +171,10 @@ class AssignmentApiTest extends TestCase ->assertJsonPath('message', 'Assignment saved successfully.'); $this->assertDatabaseHas('student_class', [ - 'student_id' => $student->id, + 'student_id' => $student->id, 'class_section_id' => $section->class_section_id, - 'semester' => 'Spring', - 'school_year' => '2025-2026', + 'semester' => 'Spring', + 'school_year' => '2025-2026', ]); } @@ -203,19 +203,19 @@ class AssignmentApiTest extends TestCase // First create $this->postJson('/api/assignments', [ - 'student_id' => $student->id, + 'student_id' => $student->id, 'class_section_id' => $sectionA->class_section_id, - 'semester' => 'Fall', - 'school_year' => '2025-2026', + 'semester' => 'Fall', + 'school_year' => '2025-2026', ])->assertCreated(); // Second call same unique key should update (per service updateOrCreate) $this->postJson('/api/assignments', [ - 'student_id' => $student->id, + 'student_id' => $student->id, 'class_section_id' => $sectionA->class_section_id, - 'semester' => 'Fall', - 'school_year' => '2025-2026', - 'description' => 'Reassigned', + 'semester' => 'Fall', + 'school_year' => '2025-2026', + 'description' => 'Reassigned', ])->assertCreated(); $this->assertEquals( @@ -228,10 +228,10 @@ class AssignmentApiTest extends TestCase ); $this->assertDatabaseHas('student_class', [ - 'student_id' => $student->id, + 'student_id' => $student->id, 'class_section_id' => $sectionA->class_section_id, - 'semester' => 'Fall', - 'school_year' => '2025-2026', + 'semester' => 'Fall', + 'school_year' => '2025-2026', ]); } diff --git a/tests/Feature/Api/V1/Attendance/LateSlipLogsControllerTest.php b/tests/Feature/Api/V1/Attendance/LateSlipLogsControllerTest.php index d88fef78..42b16cd4 100644 --- a/tests/Feature/Api/V1/Attendance/LateSlipLogsControllerTest.php +++ b/tests/Feature/Api/V1/Attendance/LateSlipLogsControllerTest.php @@ -113,7 +113,7 @@ class LateSlipLogsControllerTest extends TestCase $user = User::query()->create([ 'firstname' => 'Test', 'lastname' => 'User', - 'email' => $roleName.'@example.com', + 'email' => $roleName . '@example.com', 'cellphone' => '5555555555', 'address_street' => '123 Main', 'city' => 'City', diff --git a/tests/Feature/Api/V1/AttendanceCommentTemplateApiTest.php b/tests/Feature/Api/V1/AttendanceCommentTemplateApiTest.php index 511a4de6..f99f0e41 100644 --- a/tests/Feature/Api/V1/AttendanceCommentTemplateApiTest.php +++ b/tests/Feature/Api/V1/AttendanceCommentTemplateApiTest.php @@ -85,10 +85,10 @@ class AttendanceCommentTemplateApiTest extends TestCase $mock->shouldReceive('create') ->once() ->with(Mockery::on(function ($data) use ($payload) { - return (int) $data['min_score'] === 80 - && (int) $data['max_score'] === 100 + return (int)$data['min_score'] === 80 + && (int)$data['max_score'] === 100 && $data['template_text'] === $payload['template_text'] - && (bool) $data['is_active'] === true; + && (bool)$data['is_active'] === true; })) ->andReturn([ 'id' => 10, @@ -159,7 +159,7 @@ class AttendanceCommentTemplateApiTest extends TestCase ->once() ->with(7, Mockery::on(function ($data) { return $data['template_text'] === 'Updated comment text' - && (bool) $data['is_active'] === false; + && (bool)$data['is_active'] === false; })) ->andReturn([ 'id' => 7, @@ -221,7 +221,7 @@ class AttendanceCommentTemplateApiTest extends TestCase 'max_score' => 49, 'template_text' => 'Low attendance', 'is_active' => true, - ], + ] ]); $this->app->instance(AttendanceCommentTemplateService::class, $mock); @@ -232,4 +232,4 @@ class AttendanceCommentTemplateApiTest extends TestCase ->assertJsonCount(1, 'templates') ->assertJsonPath('templates.0.id', 1); } -} +} \ No newline at end of file diff --git a/tests/Feature/Api/V1/AttendanceTracking/AttendanceTrackingControllerTest.php b/tests/Feature/Api/V1/AttendanceTracking/AttendanceTrackingControllerTest.php index 2c5ee2e2..bfbc9683 100644 --- a/tests/Feature/Api/V1/AttendanceTracking/AttendanceTrackingControllerTest.php +++ b/tests/Feature/Api/V1/AttendanceTracking/AttendanceTrackingControllerTest.php @@ -4,7 +4,6 @@ namespace Tests\Feature\Api\V1\AttendanceTracking; use App\Services\AttendanceTracking\AttendanceTrackingService; use Mockery; -use Mockery\MockInterface; use Tests\TestCase; class AttendanceTrackingControllerTest extends TestCase @@ -15,7 +14,7 @@ class AttendanceTrackingControllerTest extends TestCase parent::tearDown(); } - protected function mockService(): MockInterface + protected function mockService(): \Mockery\MockInterface { $service = Mockery::mock(AttendanceTrackingService::class); $this->app->instance(AttendanceTrackingService::class, $service); diff --git a/tests/Feature/Api/V1/Auth/IpBanControllerTest.php b/tests/Feature/Api/V1/Auth/IpBanControllerTest.php index 834829c8..d12badd0 100644 --- a/tests/Feature/Api/V1/Auth/IpBanControllerTest.php +++ b/tests/Feature/Api/V1/Auth/IpBanControllerTest.php @@ -159,7 +159,7 @@ class IpBanControllerTest extends TestCase $user = User::query()->create([ 'firstname' => 'Test', 'lastname' => 'User', - 'email' => $roleName.'@example.com', + 'email' => $roleName . '@example.com', 'cellphone' => '5555555555', 'address_street' => '123 Main', 'city' => 'City', diff --git a/tests/Feature/Api/V1/BadgeControllerTest.php b/tests/Feature/Api/V1/BadgeControllerTest.php index d4361a44..8b6853f4 100644 --- a/tests/Feature/Api/V1/BadgeControllerTest.php +++ b/tests/Feature/Api/V1/BadgeControllerTest.php @@ -234,4 +234,4 @@ class BadgeControllerTest extends TestCase $this->postJson('/api/badges/log-print', ['user_ids' => [1]])->assertStatus(401); $this->postJson('/api/badges/pdf', ['user_ids' => [1]])->assertStatus(401); } -} +} \ No newline at end of file diff --git a/tests/Feature/Api/V1/BroadcastEmail/BroadcastEmailControllerTest.php b/tests/Feature/Api/V1/BroadcastEmail/BroadcastEmailControllerTest.php index e5018890..33ddaf1a 100644 --- a/tests/Feature/Api/V1/BroadcastEmail/BroadcastEmailControllerTest.php +++ b/tests/Feature/Api/V1/BroadcastEmail/BroadcastEmailControllerTest.php @@ -31,8 +31,7 @@ class BroadcastEmailControllerTest extends TestCase { $this->seedParentData(); - $fake = new class extends EmailService - { + $fake = new class extends EmailService { public array $sent = []; public function send( @@ -42,9 +41,9 @@ class BroadcastEmailControllerTest extends TestCase string $fromKey = 'general', array $cc = [], array $bcc = [] - ): bool { + ): bool + { $this->sent[] = compact('to', 'subject', 'html', 'fromKey', 'cc', 'bcc'); - return true; } }; diff --git a/tests/Feature/Api/V1/ClassProgress/ClassProgressControllerTest.php b/tests/Feature/Api/V1/ClassProgress/ClassProgressControllerTest.php index bf26a65d..cea23d1d 100644 --- a/tests/Feature/Api/V1/ClassProgress/ClassProgressControllerTest.php +++ b/tests/Feature/Api/V1/ClassProgress/ClassProgressControllerTest.php @@ -92,7 +92,7 @@ class ClassProgressControllerTest extends TestCase Sanctum::actingAs($user); - $response = $this->getJson('/api/v1/class-progress/'.$report->id); + $response = $this->getJson('/api/v1/class-progress/' . $report->id); $response->assertOk(); $response->assertJsonPath('status', true); @@ -110,7 +110,7 @@ class ClassProgressControllerTest extends TestCase Sanctum::actingAs($user); - $response = $this->patchJson('/api/v1/class-progress/'.$report->id, [ + $response = $this->patchJson('/api/v1/class-progress/' . $report->id, [ 'status' => 'behind', ]); @@ -132,7 +132,7 @@ class ClassProgressControllerTest extends TestCase Sanctum::actingAs($user); - $response = $this->deleteJson('/api/v1/class-progress/'.$report->id); + $response = $this->deleteJson('/api/v1/class-progress/' . $report->id); $response->assertOk(); $this->assertDatabaseMissing('class_progress_reports', [ @@ -152,7 +152,7 @@ class ClassProgressControllerTest extends TestCase Sanctum::actingAs($other); - $response = $this->getJson('/api/v1/class-progress/'.$report->id); + $response = $this->getJson('/api/v1/class-progress/' . $report->id); $response->assertStatus(403); } @@ -187,7 +187,7 @@ class ClassProgressControllerTest extends TestCase Sanctum::actingAs($user); - $response = $this->get('/api/v1/class-progress/attachments/'.$attachment->id); + $response = $this->get('/api/v1/class-progress/attachments/' . $attachment->id); $response->assertOk(); } diff --git a/tests/Feature/Api/V1/Classes/ClassSectionControllerTest.php b/tests/Feature/Api/V1/Classes/ClassSectionControllerTest.php index 34700615..3deb5d96 100644 --- a/tests/Feature/Api/V1/Classes/ClassSectionControllerTest.php +++ b/tests/Feature/Api/V1/Classes/ClassSectionControllerTest.php @@ -257,7 +257,7 @@ class ClassSectionControllerTest extends TestCase 'firstname' => 'Test', 'lastname' => 'User', 'cellphone' => '5555555555', - 'email' => $roleName.'@example.com', + 'email' => $roleName . '@example.com', 'address_street' => '123 Main', 'city' => 'City', 'state' => 'ST', diff --git a/tests/Feature/Api/V1/Communication/CommunicationControllerTest.php b/tests/Feature/Api/V1/Communication/CommunicationControllerTest.php index 340bab06..dddf92bb 100644 --- a/tests/Feature/Api/V1/Communication/CommunicationControllerTest.php +++ b/tests/Feature/Api/V1/Communication/CommunicationControllerTest.php @@ -50,8 +50,7 @@ class CommunicationControllerTest extends TestCase { $this->seedCommunicationData(); - $fake = new class extends EmailService - { + $fake = new class extends EmailService { public array $sent = []; public function send( @@ -63,7 +62,6 @@ class CommunicationControllerTest extends TestCase array $bcc = [] ): bool { $this->sent[] = compact('to', 'subject', 'html', 'fromKey', 'cc', 'bcc'); - return true; } }; diff --git a/tests/Feature/Api/V1/Family/FamilyAdminControllerTest.php b/tests/Feature/Api/V1/Family/FamilyAdminControllerTest.php index 472794fc..06903981 100644 --- a/tests/Feature/Api/V1/Family/FamilyAdminControllerTest.php +++ b/tests/Feature/Api/V1/Family/FamilyAdminControllerTest.php @@ -23,7 +23,7 @@ class FamilyAdminControllerTest extends TestCase $this->seedFamilyGuardian($familyId, $user->id); Sanctum::actingAs($user); - $response = $this->getJson('/api/v1/family-admin?student_id='.$studentId); + $response = $this->getJson('/api/v1/family-admin?student_id=' . $studentId); $response->assertOk(); $response->assertJsonPath('status', true); @@ -58,7 +58,7 @@ class FamilyAdminControllerTest extends TestCase $this->seedPayment($user->id); Sanctum::actingAs($user); - $response = $this->getJson('/api/v1/family-admin/card?family_id='.$familyId); + $response = $this->getJson('/api/v1/family-admin/card?family_id=' . $familyId); $response->assertOk(); $response->assertJsonPath('status', true); @@ -123,7 +123,7 @@ class FamilyAdminControllerTest extends TestCase 'firstname' => 'Parent', 'lastname' => 'User', 'cellphone' => '9999999999', - 'email' => 'parent'.$id.'@example.com', + 'email' => 'parent' . $id . '@example.com', 'address_street' => '123 Street', 'city' => 'City', 'state' => 'ST', @@ -163,7 +163,7 @@ class FamilyAdminControllerTest extends TestCase { return DB::table('families')->insertGetId([ 'family_code' => $code, - 'household_name' => 'Family '.$code, + 'household_name' => 'Family ' . $code, 'is_active' => 1, 'created_at' => now(), 'updated_at' => now(), diff --git a/tests/Feature/Api/V1/Family/FamilyControllerTest.php b/tests/Feature/Api/V1/Family/FamilyControllerTest.php index 735433dd..f9b1a40c 100644 --- a/tests/Feature/Api/V1/Family/FamilyControllerTest.php +++ b/tests/Feature/Api/V1/Family/FamilyControllerTest.php @@ -20,7 +20,7 @@ class FamilyControllerTest extends TestCase $this->seedFamilyStudent($familyId, $studentId); Sanctum::actingAs($user); - $response = $this->getJson('/api/v1/families/by-student/'.$studentId); + $response = $this->getJson('/api/v1/families/by-student/' . $studentId); $response->assertOk(); $response->assertJsonPath('status', true); @@ -34,7 +34,7 @@ class FamilyControllerTest extends TestCase $this->seedFamilyGuardian($familyId, $user->id); Sanctum::actingAs($user); - $response = $this->getJson('/api/v1/families/'.$familyId.'/guardians'); + $response = $this->getJson('/api/v1/families/' . $familyId . '/guardians'); $response->assertOk(); $response->assertJsonPath('status', true); @@ -292,7 +292,7 @@ class FamilyControllerTest extends TestCase { return DB::table('families')->insertGetId([ 'family_code' => $code, - 'household_name' => 'Family '.$code, + 'household_name' => 'Family ' . $code, 'is_active' => 1, 'created_at' => now(), 'updated_at' => now(), diff --git a/tests/Feature/Api/V1/Finance/EventChargeControllerTest.php b/tests/Feature/Api/V1/Finance/EventChargeControllerTest.php index 7947f84a..7d8300a6 100644 --- a/tests/Feature/Api/V1/Finance/EventChargeControllerTest.php +++ b/tests/Feature/Api/V1/Finance/EventChargeControllerTest.php @@ -28,7 +28,7 @@ class EventChargeControllerTest extends TestCase { $charge = $this->makeCharge(); - $this->getJson('/api/v1/finance/event-charges/'.$charge->id) + $this->getJson('/api/v1/finance/event-charges/' . $charge->id) ->assertStatus(401); } @@ -37,7 +37,7 @@ class EventChargeControllerTest extends TestCase $this->actingAsApiAdministrator(); $charge = $this->makeCharge(); - $this->getJson('/api/v1/finance/event-charges/'.$charge->id) + $this->getJson('/api/v1/finance/event-charges/' . $charge->id) ->assertOk() ->assertJsonPath('ok', true) ->assertJsonPath('event_charge.id', $charge->id) @@ -57,7 +57,7 @@ class EventChargeControllerTest extends TestCase $this->actingAsApiAdministrator(); $charge = $this->makeCharge(); - $this->putJson('/api/v1/finance/event-charges/'.$charge->id, [ + $this->putJson('/api/v1/finance/event-charges/' . $charge->id, [ 'event_name' => 'Museum Visit', 'amount' => 40.50, ]) @@ -76,7 +76,7 @@ class EventChargeControllerTest extends TestCase $this->actingAsApiAdministrator(); $charge = $this->makeCharge(['charged' => 0]); - $this->postJson('/api/v1/finance/event-charges/'.$charge->id.'/approve') + $this->postJson('/api/v1/finance/event-charges/' . $charge->id . '/approve') ->assertOk() ->assertJsonPath('ok', true); @@ -91,7 +91,7 @@ class EventChargeControllerTest extends TestCase $this->actingAsApiAdministrator(); $charge = $this->makeCharge(['charged' => 1]); - $this->postJson('/api/v1/finance/event-charges/'.$charge->id.'/void') + $this->postJson('/api/v1/finance/event-charges/' . $charge->id . '/void') ->assertOk() ->assertJsonPath('ok', true); @@ -106,7 +106,7 @@ class EventChargeControllerTest extends TestCase $this->actingAsApiAdministrator(); $charge = $this->makeCharge(['charged' => 1]); - $this->deleteJson('/api/v1/finance/event-charges/'.$charge->id) + $this->deleteJson('/api/v1/finance/event-charges/' . $charge->id) ->assertOk() ->assertJsonPath('ok', true); diff --git a/tests/Feature/Api/V1/Frontend/FrontendControllerTest.php b/tests/Feature/Api/V1/Frontend/FrontendControllerTest.php index 22a00ea8..fb68a7b2 100644 --- a/tests/Feature/Api/V1/Frontend/FrontendControllerTest.php +++ b/tests/Feature/Api/V1/Frontend/FrontendControllerTest.php @@ -49,7 +49,7 @@ class FrontendControllerTest extends TestCase $user = User::query()->create([ 'firstname' => 'Test', 'lastname' => 'User', - 'email' => $roleName.'@example.com', + 'email' => $roleName . '@example.com', 'cellphone' => '5555555555', 'address_street' => '123 Main', 'city' => 'City', diff --git a/tests/Feature/Api/V1/Frontend/InfoIconControllerTest.php b/tests/Feature/Api/V1/Frontend/InfoIconControllerTest.php index e04e2247..ebd0a5e2 100644 --- a/tests/Feature/Api/V1/Frontend/InfoIconControllerTest.php +++ b/tests/Feature/Api/V1/Frontend/InfoIconControllerTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\Frontend; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Facades\DB; use Laravel\Sanctum\Sanctum; use Tests\TestCase; diff --git a/tests/Feature/Api/V1/Frontend/LandingPageControllerTest.php b/tests/Feature/Api/V1/Frontend/LandingPageControllerTest.php index cbe73476..d60af1b5 100644 --- a/tests/Feature/Api/V1/Frontend/LandingPageControllerTest.php +++ b/tests/Feature/Api/V1/Frontend/LandingPageControllerTest.php @@ -57,7 +57,7 @@ class LandingPageControllerTest extends TestCase $user = User::query()->create([ 'firstname' => 'Test', 'lastname' => 'User', - 'email' => $roleName.'@example.com', + 'email' => $roleName . '@example.com', 'cellphone' => '5555555555', 'address_street' => '123 Main', 'city' => 'City', diff --git a/tests/Feature/Api/V1/Frontend/PageControllerTest.php b/tests/Feature/Api/V1/Frontend/PageControllerTest.php index 2b7df224..538d3cea 100644 --- a/tests/Feature/Api/V1/Frontend/PageControllerTest.php +++ b/tests/Feature/Api/V1/Frontend/PageControllerTest.php @@ -15,7 +15,7 @@ class PageControllerTest extends TestCase { $dir = public_path('html'); File::ensureDirectoryExists($dir); - File::put($dir.'/privacy_policy.html', '

Privacy

'); + File::put($dir . '/privacy_policy.html', '

Privacy

'); $response = $this->getJson('/api/v1/pages/privacy'); @@ -28,7 +28,7 @@ class PageControllerTest extends TestCase { $dir = public_path('html'); File::ensureDirectoryExists($dir); - File::delete($dir.'/help_center.html'); + File::delete($dir . '/help_center.html'); $response = $this->getJson('/api/v1/pages/help'); diff --git a/tests/Feature/Api/V1/FullSurface/ApiAcademicAttendanceFullSurfaceContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiAcademicAttendanceFullSurfaceContractTest.php index 9e12e651..a7579826 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiAcademicAttendanceFullSurfaceContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiAcademicAttendanceFullSurfaceContractTest.php @@ -12,9 +12,9 @@ use Tests\TestCase; */ class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase { - use AssertsE2EApiResponses; use RefreshDatabase; use SeedsE2ETestFixtures; + use AssertsE2EApiResponses; public function test_academic_attendance_and_grading_surfaces_have_controlled_contracts(): void { @@ -24,21 +24,21 @@ class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase foreach ($this->teacherGetEndpoints($world) as $uri) { $response = $this->getJson($uri); - $this->assertNoServerError($response, 'Teacher GET '.$uri); - $this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Teacher GET '.$uri); + $this->assertNoServerError($response, 'Teacher GET ' . $uri); + $this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Teacher GET ' . $uri); } foreach ($this->teacherMutationEndpoints($world) as [$method, $uri, $payload]) { $response = $this->json($method, $uri, $payload); - $this->assertNoServerError($response, 'Teacher '.$method.' '.$uri); - $this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Teacher '.$method.' '.$uri); + $this->assertNoServerError($response, 'Teacher ' . $method . ' ' . $uri); + $this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Teacher ' . $method . ' ' . $uri); } $this->actingAsApiAdministrator(); foreach ($this->adminAcademicEndpoints($world) as [$method, $uri, $payload]) { $response = $this->json($method, $uri, $payload); - $this->assertNoServerError($response, 'Admin academic '.$method.' '.$uri); - $this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin academic '.$method.' '.$uri); + $this->assertNoServerError($response, 'Admin academic ' . $method . ' ' . $uri); + $this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin academic ' . $method . ' ' . $uri); } } @@ -49,35 +49,35 @@ class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase $studentId = (int) $world['student_id']; return [ - '/api/v1/teachers/classes?class_section_id='.$classSectionId, - '/api/v1/teacher/class-view?class_section_id='.$classSectionId, + '/api/v1/teachers/classes?class_section_id=' . $classSectionId, + '/api/v1/teacher/class-view?class_section_id=' . $classSectionId, '/api/v1/teacher/no-classes', '/api/v1/teacher/select-semester', - '/api/v1/teacher/homework-list?class_section_id='.$classSectionId, - '/api/v1/teacher/add-homework?class_section_id='.$classSectionId, - '/api/v1/teacher/add-quiz?class_section_id='.$classSectionId, - '/api/v1/teacher/add-quiz-column-form?class_section_id='.$classSectionId, - '/api/v1/teacher/add-midterm-exam?class_section_id='.$classSectionId, - '/api/v1/teacher/add-final-exam?class_section_id='.$classSectionId, - '/api/v1/teacher/add-participation?class_section_id='.$classSectionId, - '/api/v1/teacher/add-project?class_section_id='.$classSectionId, + '/api/v1/teacher/homework-list?class_section_id=' . $classSectionId, + '/api/v1/teacher/add-homework?class_section_id=' . $classSectionId, + '/api/v1/teacher/add-quiz?class_section_id=' . $classSectionId, + '/api/v1/teacher/add-quiz-column-form?class_section_id=' . $classSectionId, + '/api/v1/teacher/add-midterm-exam?class_section_id=' . $classSectionId, + '/api/v1/teacher/add-final-exam?class_section_id=' . $classSectionId, + '/api/v1/teacher/add-participation?class_section_id=' . $classSectionId, + '/api/v1/teacher/add-project?class_section_id=' . $classSectionId, '/api/v1/teacher/teacher-assignment', '/api/v1/teacher/exam-drafts', '/api/v1/teacher/drafts', '/api/v1/teacher/inventory/books/distribute', '/api/v1/teacher/print-requests/context', '/api/v1/teacher/absence-vacation', - '/api/v1/teacher/showupdate-attendance?class_section_id='.$classSectionId, - '/api/v1/teacher/showupdate_attendance?class_section_id='.$classSectionId, - '/api/v1/teacher/scores?class_section_id='.$classSectionId, + '/api/v1/teacher/showupdate-attendance?class_section_id=' . $classSectionId, + '/api/v1/teacher/showupdate_attendance?class_section_id=' . $classSectionId, + '/api/v1/teacher/scores?class_section_id=' . $classSectionId, '/api/v1/teacher/calendar', - '/api/v1/teacher/class-progress-submit?class_section_id='.$classSectionId, - '/api/v1/teacher/class-progress-history?class_section_id='.$classSectionId, - '/api/v1/teacher/class-progress-view?class_section_id='.$classSectionId, + '/api/v1/teacher/class-progress-submit?class_section_id=' . $classSectionId, + '/api/v1/teacher/class-progress-history?class_section_id=' . $classSectionId, + '/api/v1/teacher/class-progress-view?class_section_id=' . $classSectionId, '/api/v1/teacher/competition-scores', - '/api/v1/attendance/teacher/grid?class_section_id='.$classSectionId, - '/api/v1/attendance/teacher/form?class_section_id='.$classSectionId, - '/api/v1/attendance/admin/daily?date=2025-10-05&class_section_id='.$classSectionId, + '/api/v1/attendance/teacher/grid?class_section_id=' . $classSectionId, + '/api/v1/attendance/teacher/form?class_section_id=' . $classSectionId, + '/api/v1/attendance/admin/daily?date=2025-10-05&class_section_id=' . $classSectionId, '/api/v1/attendance/staff/month?month=2025-10', '/api/v1/attendance/staff/admins', '/api/v1/attendance/late-slip-logs', @@ -87,7 +87,7 @@ class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase '/api/v1/attendance/management/dashboard', '/api/v1/attendance-tracking/pending-violations', '/api/v1/attendance-tracking/notified-violations', - '/api/v1/attendance-tracking/student-case/'.$studentId, + '/api/v1/attendance-tracking/student-case/' . $studentId, '/api/v1/attendance-tracking/compose', '/api/v1/attendance-tracking/parents-info', '/api/v1/attendance-comment-templates', @@ -96,15 +96,15 @@ class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase '/api/v1/attendance-templates', '/api/v1/assignments', '/api/v1/assignments/class-assignment-data', - '/api/v1/scores/overview?class_section_id='.$classSectionId, - '/api/v1/scores/homework?class_section_id='.$classSectionId, - '/api/v1/scores/quiz?class_section_id='.$classSectionId, - '/api/v1/scores/project?class_section_id='.$classSectionId, - '/api/v1/scores/midterm?class_section_id='.$classSectionId, - '/api/v1/scores/final?class_section_id='.$classSectionId, - '/api/v1/scores/participation?class_section_id='.$classSectionId, - '/api/v1/grading/homework-tracking?class_section_id='.$classSectionId, - '/api/v1/reports/report-cards/meta?class_section_id='.$classSectionId, + '/api/v1/scores/overview?class_section_id=' . $classSectionId, + '/api/v1/scores/homework?class_section_id=' . $classSectionId, + '/api/v1/scores/quiz?class_section_id=' . $classSectionId, + '/api/v1/scores/project?class_section_id=' . $classSectionId, + '/api/v1/scores/midterm?class_section_id=' . $classSectionId, + '/api/v1/scores/final?class_section_id=' . $classSectionId, + '/api/v1/scores/participation?class_section_id=' . $classSectionId, + '/api/v1/grading/homework-tracking?class_section_id=' . $classSectionId, + '/api/v1/reports/report-cards/meta?class_section_id=' . $classSectionId, ]; } @@ -159,8 +159,8 @@ class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase private function adminAcademicEndpoints(array $world): array { return [ - ['GET', '/api/v1/reports/report-cards?student_id='.$world['student_id'], []], - ['GET', '/api/v1/reports/stickers?student_id='.$world['student_id'], []], + ['GET', '/api/v1/reports/report-cards?student_id=' . $world['student_id'], []], + ['GET', '/api/v1/reports/stickers?student_id=' . $world['student_id'], []], ['GET', '/api/v1/badges/form-options', []], ['POST', '/api/v1/print-requests', ['title' => 'Contract Probe', 'copies' => 1, 'needed_by' => '2025-10-12']], ['GET', '/api/v1/print-requests/admin', []], diff --git a/tests/Feature/Api/V1/FullSurface/ApiAccountStatusLifecycleContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiAccountStatusLifecycleContractTest.php index e1b0373e..fae87403 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiAccountStatusLifecycleContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiAccountStatusLifecycleContractTest.php @@ -24,7 +24,7 @@ class ApiAccountStatusLifecycleContractTest extends FullSurfaceE2EContractCase $response = $this->requestAs($actor, 'GET', $uri); $this->assertControlled($response, 'GET', $uri); - $this->assertNoServerError($response, 'account status '.$status.' at GET '.$uri); + $this->assertNoServerError($response, 'account status ' . $status . ' at GET ' . $uri); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiAdminOperationsFullSurfaceContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiAdminOperationsFullSurfaceContractTest.php index cc645853..5e572473 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiAdminOperationsFullSurfaceContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiAdminOperationsFullSurfaceContractTest.php @@ -12,9 +12,9 @@ use Tests\TestCase; */ class ApiAdminOperationsFullSurfaceContractTest extends TestCase { - use AssertsE2EApiResponses; use RefreshDatabase; use SeedsE2ETestFixtures; + use AssertsE2EApiResponses; public function test_administrator_operational_surface_responds_with_controlled_contracts(): void { @@ -24,19 +24,19 @@ class ApiAdminOperationsFullSurfaceContractTest extends TestCase foreach ($this->adminGetEndpoints($world) as $uri) { $response = $this->getJson($uri); - $this->assertNoServerError($response, 'Admin GET '.$uri); - $this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin GET '.$uri); + $this->assertNoServerError($response, 'Admin GET ' . $uri); + $this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin GET ' . $uri); } foreach ($this->adminMutationEndpoints($world, $admin->id) as [$method, $uri, $payload]) { $response = $this->json($method, $uri, $payload); - $this->assertNoServerError($response, 'Admin '.$method.' '.$uri); - $this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin '.$method.' '.$uri); + $this->assertNoServerError($response, 'Admin ' . $method . ' ' . $uri); + $this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin ' . $method . ' ' . $uri); } } /** - * @param array $world + * @param array $world * @return list */ private function adminGetEndpoints(array $world): array @@ -76,7 +76,7 @@ class ApiAdminOperationsFullSurfaceContractTest extends TestCase '/api/v1/administrator/flags/students/1', '/api/v1/administrator/flags/processed', '/api/v1/administrator/flags/analysis', - '/api/v1/administrator/grading/homework-tracking?class_section_id='.$classSectionId, + '/api/v1/administrator/grading/homework-tracking?class_section_id=' . $classSectionId, '/api/v1/administrator/expenses', '/api/v1/administrator/expenses/options', '/api/v1/administrator/expenses/1', @@ -110,13 +110,13 @@ class ApiAdminOperationsFullSurfaceContractTest extends TestCase '/api/v1/class-sections', '/api/v1/classes', '/api/v1/users', - '/api/v1/users/'.$world['parent_id'], - '/api/v1/students/'.$studentId, + '/api/v1/users/' . $world['parent_id'], + '/api/v1/students/' . $studentId, ]; } /** - * @param array $world + * @param array $world * @return list}> */ private function adminMutationEndpoints(array $world, int $adminId): array diff --git a/tests/Feature/Api/V1/FullSurface/ApiAttachmentUploadContentSafetyContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiAttachmentUploadContentSafetyContractTest.php index 9fa1cebf..573fba77 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiAttachmentUploadContentSafetyContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiAttachmentUploadContentSafetyContractTest.php @@ -43,7 +43,7 @@ class ApiAttachmentUploadContentSafetyContractTest extends FullSurfaceE2EContrac continue; } - $path = $this->materializePath($route->uri()).'?filename=../../.env&path=../../storage/logs/laravel.log'; + $path = $this->materializePath($route->uri()) . '?filename=../../.env&path=../../storage/logs/laravel.log'; $response = $this->actingAs($this->actorFor($route->uri()), 'api')->getJson($path); $this->assertStatusIn($response, [200, 204, 400, 401, 403, 404, 409, 422], "GET {$route->uri()} path traversal probe"); diff --git a/tests/Feature/Api/V1/FullSurface/ApiAuditLogAndAdministrativeTraceabilityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiAuditLogAndAdministrativeTraceabilityContractTest.php index 543756d7..f4ad154c 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiAuditLogAndAdministrativeTraceabilityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiAuditLogAndAdministrativeTraceabilityContractTest.php @@ -21,8 +21,8 @@ class ApiAuditLogAndAdministrativeTraceabilityContractTest extends FullSurfaceE2 $this->assertNoServerError($response, "$method $uri admin mutation traceability"); $this->assertControlled($response, $method, $uri); - $this->assertStringNotContainsStringIgnoringCase('audit_log_id', $response->getContent(), $uri.' should not leak raw internal audit identifiers by accident.'); - $this->assertStringNotContainsStringIgnoringCase('stack_trace', $response->getContent(), $uri.' should not leak stack traces in mutation responses.'); + $this->assertStringNotContainsStringIgnoringCase('audit_log_id', $response->getContent(), $uri . ' should not leak raw internal audit identifiers by accident.'); + $this->assertStringNotContainsStringIgnoringCase('stack_trace', $response->getContent(), $uri . ' should not leak stack traces in mutation responses.'); } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiAuthenticationLifecycleDepthContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiAuthenticationLifecycleDepthContractTest.php index 7c244590..a623a1d4 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiAuthenticationLifecycleDepthContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiAuthenticationLifecycleDepthContractTest.php @@ -20,12 +20,12 @@ class ApiAuthenticationLifecycleDepthContractTest extends FullSurfaceE2EContract 'password' => 'password', ]); - $this->assertNoServerError($response, 'valid login at '.$path); + $this->assertNoServerError($response, 'valid login at ' . $path); if ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300) { $this->assertTrue( $response->json('token') !== null || $response->json('access_token') !== null || $response->json('user') !== null, - $path.' must return a usable login contract, not a mystery envelope.' + $path . ' must return a usable login contract, not a mystery envelope.' ); } } @@ -36,18 +36,18 @@ class ApiAuthenticationLifecycleDepthContractTest extends FullSurfaceE2EContract 'password' => 'definitely-wrong-password', ]); - $this->assertStatusIn($response, [400, 401, 403, 419, 422], 'invalid login at '.$path); - $this->assertNoServerError($response, 'invalid login at '.$path); + $this->assertStatusIn($response, [400, 401, 403, 419, 422], 'invalid login at ' . $path); + $this->assertNoServerError($response, 'invalid login at ' . $path); } foreach (['/api/v1/auth/me', '/api/v1/me', '/api/user'] as $path) { $response = $this->actingAs($this->admin, 'api')->getJson($path); - $this->assertNoServerError($response, 'authenticated identity lookup at '.$path); + $this->assertNoServerError($response, 'authenticated identity lookup at ' . $path); if ($response->getStatusCode() === 200) { $this->assertTrue( $response->json('user') !== null || $response->json('id') !== null || $response->json('data') !== null, - $path.' must expose a stable identity payload.' + $path . ' must expose a stable identity payload.' ); } } @@ -56,10 +56,10 @@ class ApiAuthenticationLifecycleDepthContractTest extends FullSurfaceE2EContract $first = $this->actingAs($this->admin, 'api')->postJson($path); $second = $this->actingAs($this->admin, 'api')->postJson($path); - $this->assertNoServerError($first, 'first logout at '.$path); - $this->assertNoServerError($second, 'repeat logout at '.$path); - $this->assertStatusIn($first, [200, 202, 204, 302, 401, 404, 419, 422], 'first logout at '.$path); - $this->assertStatusIn($second, [200, 202, 204, 302, 401, 404, 419, 422], 'repeat logout at '.$path); + $this->assertNoServerError($first, 'first logout at ' . $path); + $this->assertNoServerError($second, 'repeat logout at ' . $path); + $this->assertStatusIn($first, [200, 202, 204, 302, 401, 404, 419, 422], 'first logout at ' . $path); + $this->assertStatusIn($second, [200, 202, 204, 302, 401, 404, 419, 422], 'repeat logout at ' . $path); } } @@ -75,16 +75,16 @@ class ApiAuthenticationLifecycleDepthContractTest extends FullSurfaceE2EContract $uri = $route->uri(); $response = $this->json($method, $this->materializePath($uri), [ - 'email' => 'nobody.'.uniqid().'@example.test', + 'email' => 'nobody.' . uniqid() . '@example.test', 'password' => 'password', 'password_confirmation' => 'not-the-same', 'token' => 'not-a-real-token', ]); $this->assertControlled($response, $method, $uri); - $this->assertNoServerError($response, $method.' '.$uri); - $this->assertStringNotContainsStringIgnoringCase('select * from', $response->getContent(), $uri.' must not leak account lookup SQL.'); - $this->assertStringNotContainsStringIgnoringCase('No query results for model', $response->getContent(), $uri.' must not leak framework model lookups.'); + $this->assertNoServerError($response, $method . ' ' . $uri); + $this->assertStringNotContainsStringIgnoringCase('select * from', $response->getContent(), $uri . ' must not leak account lookup SQL.'); + $this->assertStringNotContainsStringIgnoringCase('No query results for model', $response->getContent(), $uri . ' must not leak framework model lookups.'); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiAuthorizationCacheInvalidationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiAuthorizationCacheInvalidationContractTest.php index e31ec3ea..5f567ec5 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiAuthorizationCacheInvalidationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiAuthorizationCacheInvalidationContractTest.php @@ -22,8 +22,8 @@ class ApiAuthorizationCacheInvalidationContractTest extends FullSurfaceE2EContra $response = $this->requestAs($this->parent, $method, $uri, $payload); - $this->assertStatusIn($response, [401, 403, 404, 405, 419, 422], 'parent privilege escalation should be blocked at '.$method.' '.$uri); - $this->assertNoServerError($response, 'permission cache escalation probe at '.$method.' '.$uri); + $this->assertStatusIn($response, [401, 403, 404, 405, 419, 422], 'parent privilege escalation should be blocked at ' . $method . ' ' . $uri); + $this->assertNoServerError($response, 'permission cache escalation probe at ' . $method . ' ' . $uri); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch11RouteRegressionNetTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch11RouteRegressionNetTest.php index 45c19d84..fab61286 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch11RouteRegressionNetTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch11RouteRegressionNetTest.php @@ -24,7 +24,7 @@ class ApiBatch11RouteRegressionNetTest extends FullSurfaceE2EContractCase foreach ($families as $family => $needles) { $this->assertNotEmpty( $this->apiRoutesContainingAny($needles), - 'Batch 11 expects at least one route for the '.$family.' family. If this fails, update the route catalog instead of pretending the family vanished.' + 'Batch 11 expects at least one route for the ' . $family . ' family. If this fails, update the route catalog instead of pretending the family vanished.' ); } } @@ -53,7 +53,7 @@ class ApiBatch11RouteRegressionNetTest extends FullSurfaceE2EContractCase ])->json($method, $this->materializePath($uri), $payload); $this->assertControlled($response, $method, $uri); - $this->assertNoServerError($response, 'batch 11 combined hostile probe at '.$method.' '.$uri); + $this->assertNoServerError($response, 'batch 11 combined hostile probe at ' . $method . ' ' . $uri); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch12AttachmentLifecycleContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch12AttachmentLifecycleContractTest.php index d8066f2e..6fb6941e 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch12AttachmentLifecycleContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch12AttachmentLifecycleContractTest.php @@ -2,9 +2,10 @@ namespace Tests\Feature\Api\V1\FullSurface; -use Illuminate\Http\UploadedFile; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; +use Illuminate\Http\UploadedFile; + class ApiBatch12AttachmentLifecycleContractTest extends FullSurfaceE2EContractCase { public function test_attachment_upload_routes_handle_multiple_file_shapes_cleanly(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14AcademicPromotionRollbackIntegrityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14AcademicPromotionRollbackIntegrityContractTest.php index cee04a48..d73cad49 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14AcademicPromotionRollbackIntegrityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14AcademicPromotionRollbackIntegrityContractTest.php @@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14AcademicPromotionRollbackIntegrityContractTest extends FullSurfaceE2EContractCase { - public function test_promotion_and_school_year_routes_reject_unsafe_rollback_payloads(): void +public function test_promotion_and_school_year_routes_reject_unsafe_rollback_payloads(): void { foreach (array_slice($this->apiRoutesContainingAny(['promotion', 'promote', 'school-year', 'semester', 'close', 'reopen', 'rollback']), 0, 45) as $route) { $method = $this->primaryMethod($route); @@ -22,12 +22,10 @@ class ApiBatch14AcademicPromotionRollbackIntegrityContractTest extends FullSurfa { foreach (array_slice($this->apiRoutesContainingAny(['promotion', 'school-year', 'close', 'reopen']), 0, 30) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { - continue; - } + if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; } foreach ([$this->teacher, $this->parent, $this->studentUser] as $actor) { $response = $this->requestAs($actor, $method, $route->uri(), ['force' => true, 'confirmed' => true, 'school_year_id' => $this->ids['schoolYearId']]); - $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri()); + $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri()); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14AccountEnumerationAndIdentityPrivacyContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14AccountEnumerationAndIdentityPrivacyContractTest.php index a6af47d2..eeff406e 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14AccountEnumerationAndIdentityPrivacyContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14AccountEnumerationAndIdentityPrivacyContractTest.php @@ -6,15 +6,13 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14AccountEnumerationAndIdentityPrivacyContractTest extends FullSurfaceE2EContractCase { - public function test_identity_recovery_routes_do_not_reveal_whether_user_exists(): void +public function test_identity_recovery_routes_do_not_reveal_whether_user_exists(): void { $routes = $this->apiRoutesContainingAny(['forgot', 'password', 'reset', 'verify', 'verification', 'recovery']); foreach (array_slice($routes, 0, 30) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { - continue; - } - foreach ([$this->admin->email, 'missing-user-'.uniqid().'@example.test'] as $email) { + if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { continue; } + foreach ([$this->admin->email, 'missing-user-' . uniqid() . '@example.test'] as $email) { $response = $this->json($method, $this->materializePath($route->uri()), ['email' => $email, 'token' => 'invalid-token', 'password' => 'NewPassword123!', 'password_confirmation' => 'NewPassword123!']); $this->assertControlled($response, $method, $route->uri()); $body = strtolower($response->getContent()); @@ -33,7 +31,7 @@ class ApiBatch14AccountEnumerationAndIdentityPrivacyContractTest extends FullSur $this->assertControlled($response, $method, $route->uri()); $body = strtolower($response->getContent()); foreach (['password', 'remember_token', 'two_factor', 'api_token', 'provider_token', 'secret'] as $forbidden) { - $this->assertStringNotContainsString($forbidden, $body, $route->uri().' leaked identity internals.'); + $this->assertStringNotContainsString($forbidden, $body, $route->uri() . ' leaked identity internals.'); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14AdminDelegationApprovalWorkflowContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14AdminDelegationApprovalWorkflowContractTest.php index 32b8eec1..bb444c69 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14AdminDelegationApprovalWorkflowContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14AdminDelegationApprovalWorkflowContractTest.php @@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14AdminDelegationApprovalWorkflowContractTest extends FullSurfaceE2EContractCase { - public function test_approval_and_delegation_routes_reject_forged_approval_metadata(): void +public function test_approval_and_delegation_routes_reject_forged_approval_metadata(): void { foreach (array_slice($this->apiRoutesContainingAny(['approve', 'approval', 'delegate', 'delegation', 'authorize', 'permission', 'role', 'impersonate']), 0, 50) as $route) { $method = $this->primaryMethod($route); @@ -20,12 +20,10 @@ class ApiBatch14AdminDelegationApprovalWorkflowContractTest extends FullSurfaceE { foreach (array_slice($this->apiRoutesContainingAny(['approve', 'approval', 'delegate', 'permission', 'role']), 0, 35) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { - continue; - } + if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; } foreach ([$this->teacher, $this->parent, $this->studentUser] as $actor) { $response = $this->requestAs($actor, $method, $route->uri(), ['approved' => true, 'permissions' => ['*'], 'role' => 'administrator', 'force' => true]); - $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri()); + $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri()); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14ApiConsumerContractCompatibilityTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14ApiConsumerContractCompatibilityTest.php index 01135515..b61722d2 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14ApiConsumerContractCompatibilityTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14ApiConsumerContractCompatibilityTest.php @@ -6,17 +6,15 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14ApiConsumerContractCompatibilityTest extends FullSurfaceE2EContractCase { - public function test_core_identity_contracts_remain_compatible_for_web_mobile_and_api_clients(): void +public function test_core_identity_contracts_remain_compatible_for_web_mobile_and_api_clients(): void { foreach (array_slice($this->apiRoutesContainingAny(['login', 'auth/me', 'me', 'frontend', 'profile']), 0, 25) as $route) { $method = $this->primaryMethod($route); foreach ([['Accept' => 'application/json', 'X-Client' => 'web'], ['Accept' => 'application/json', 'X-Client' => 'mobile', 'X-App-Version' => '1.0.0'], ['Accept' => 'application/vnd.alrahma.v1+json', 'X-Client' => 'api-consumer']] as $headers) { $response = $this->withHeaders($headers)->actingAs($this->actorFor($route->uri()), 'api')->json($method, $this->materializePath($route->uri()), $this->payloadFor($method, $route->uri())); $this->assertControlled($response, $method, $route->uri()); - $this->assertJsonResponseWhenSuccessful($response, $method.' '.$route->uri()); - if ($response->isSuccessful()) { - $this->assertStringNotContainsString('undefined index', strtolower($response->getContent())); - } + $this->assertJsonResponseWhenSuccessful($response, $method . ' ' . $route->uri()); + if ($response->isSuccessful()) { $this->assertStringNotContainsString('undefined index', strtolower($response->getContent())); } } } } @@ -25,15 +23,13 @@ class ApiBatch14ApiConsumerContractCompatibilityTest extends FullSurfaceE2EContr { foreach (array_slice($this->apiRoutesContainingAny(['login', 'auth/login']), 0, 10) as $route) { $method = $this->primaryMethod($route); - if ($method !== 'POST') { - continue; - } + if ($method !== 'POST') { continue; } $response = $this->json($method, $this->materializePath($route->uri()), ['email' => $this->admin->email, 'password' => 'password']); $this->assertControlled($response, $method, $route->uri()); if ($response->isSuccessful() && $this->isJsonString($response->getContent())) { $data = $response->json(); - $this->assertTrue(isset($data['token']) || isset($data['access_token']), $route->uri().' should expose token/access_token when login succeeds.'); - $this->assertArrayHasKey('user', $data, $route->uri().' should expose user when login succeeds.'); + $this->assertTrue(isset($data['token']) || isset($data['access_token']), $route->uri() . ' should expose token/access_token when login succeeds.'); + $this->assertArrayHasKey('user', $data, $route->uri() . ' should expose user when login succeeds.'); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14AttendanceDeviceAndKioskAbuseContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14AttendanceDeviceAndKioskAbuseContractTest.php index 4b9220d0..1286d88a 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14AttendanceDeviceAndKioskAbuseContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14AttendanceDeviceAndKioskAbuseContractTest.php @@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14AttendanceDeviceAndKioskAbuseContractTest extends FullSurfaceE2EContractCase { - public function test_kiosk_scanner_and_attendance_routes_reject_forged_device_identity(): void +public function test_kiosk_scanner_and_attendance_routes_reject_forged_device_identity(): void { foreach (array_slice($this->apiRoutesContainingAny(['attendance', 'scanner', 'scan', 'kiosk', 'badge', 'dismissal', 'late']), 0, 55) as $route) { $method = $this->primaryMethod($route); @@ -22,12 +22,10 @@ class ApiBatch14AttendanceDeviceAndKioskAbuseContractTest extends FullSurfaceE2E { foreach (array_slice($this->apiRoutesContainingAny(['attendance', 'scan', 'dismissal', 'late']), 0, 30) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { - continue; - } + if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { continue; } foreach ([$this->studentUser, $this->parent] as $actor) { $response = $this->requestAs($actor, $method, $route->uri(), ['student_id' => $this->ids['studentId'], 'status' => 'present', 'verified_by_device' => true, 'override_reason' => 'parent approved']); - $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri()); + $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri()); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14AuditTrailTamperResistanceContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14AuditTrailTamperResistanceContractTest.php index b7c58626..b40a8c8e 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14AuditTrailTamperResistanceContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14AuditTrailTamperResistanceContractTest.php @@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14AuditTrailTamperResistanceContractTest extends FullSurfaceE2EContractCase { - public function test_audit_and_log_routes_reject_client_supplied_actor_and_timestamp_fields(): void +public function test_audit_and_log_routes_reject_client_supplied_actor_and_timestamp_fields(): void { foreach (array_slice($this->apiRoutesContainingAny(['audit', 'log', 'activity', 'history', 'trace']), 0, 35) as $route) { $method = $this->primaryMethod($route); @@ -22,12 +22,10 @@ class ApiBatch14AuditTrailTamperResistanceContractTest extends FullSurfaceE2ECon { foreach (array_slice($this->apiRoutesContainingAny(['audit', 'log', 'history', 'activity']), 0, 25) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { - continue; - } + if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; } foreach ([$this->parent, $this->teacher, $this->studentUser] as $actor) { $response = $this->requestAs($actor, $method, $route->uri(), ['action' => 'clear', 'purge' => true, 'rewrite' => true]); - $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri()); + $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri()); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14BulkAssignmentCollisionContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14BulkAssignmentCollisionContractTest.php index e9a874db..4f1e3342 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14BulkAssignmentCollisionContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14BulkAssignmentCollisionContractTest.php @@ -6,13 +6,11 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14BulkAssignmentCollisionContractTest extends FullSurfaceE2EContractCase { - public function test_bulk_assignment_routes_handle_duplicate_and_conflicting_ids_cleanly(): void +public function test_bulk_assignment_routes_handle_duplicate_and_conflicting_ids_cleanly(): void { foreach (array_slice($this->apiRoutesContainingAny(['assign', 'assignment', 'enroll', 'bulk', 'batch', 'class', 'teacher', 'student']), 0, 50) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { - continue; - } + if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { continue; } $response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $this->payloadFor($method, $route->uri()) + [ 'student_ids' => [$this->ids['studentId'], $this->ids['studentId'], 99999999], 'teacher_ids' => [$this->teacher->id, $this->teacher->id, $this->parent->id], 'class_section_ids' => [$this->ids['classSectionId'], $this->ids['classSectionId'], 99999999], 'parent_ids' => [$this->ids['parentId'], $this->ids['parentId'], 99999999], 'force' => true, 'overwrite' => true, @@ -29,12 +27,10 @@ class ApiBatch14BulkAssignmentCollisionContractTest extends FullSurfaceE2EContra { foreach (array_slice($this->apiRoutesContainingAny(['assign', 'bulk', 'batch', 'class-sections', 'teacher-class', 'enroll']), 0, 30) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { - continue; - } + if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; } foreach ([$this->parent, $this->studentUser] as $actor) { $response = $this->requestAs($actor, $method, $route->uri(), ['student_ids' => [$this->ids['studentId']], 'teacher_ids' => [$this->teacher->id], 'class_section_ids' => [$this->ids['classSectionId']], 'all' => true, 'force' => true]); - $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri()); + $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri()); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14CrossModuleInvariantRiskRegisterTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14CrossModuleInvariantRiskRegisterTest.php index 5e38210d..05081135 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14CrossModuleInvariantRiskRegisterTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14CrossModuleInvariantRiskRegisterTest.php @@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14CrossModuleInvariantRiskRegisterTest extends FullSurfaceE2EContractCase { - public function test_batch14_route_families_have_cross_module_risk_coverage(): void +public function test_batch14_route_families_have_cross_module_risk_coverage(): void { $riskFamilies = [ 'session-cookie-boundary' => ['auth', 'login', 'frontend'], @@ -22,7 +22,7 @@ class ApiBatch14CrossModuleInvariantRiskRegisterTest extends FullSurfaceE2EContr ]; foreach ($riskFamilies as $name => $needles) { - $this->assertNotEmpty($this->apiRoutesContainingAny($needles), 'Batch 14 expected route coverage for '.$name); + $this->assertNotEmpty($this->apiRoutesContainingAny($needles), 'Batch 14 expected route coverage for ' . $name); } } @@ -32,7 +32,7 @@ class ApiBatch14CrossModuleInvariantRiskRegisterTest extends FullSurfaceE2EContr $mutations = array_filter($this->apiRoutesContainingAny([$family]), function ($route): bool { return in_array($this->primaryMethod($route), ['POST', 'PUT', 'PATCH', 'DELETE'], true); }); - $this->assertNotEmpty($mutations, 'Batch 14 expected mutating route family: '.$family); + $this->assertNotEmpty($mutations, 'Batch 14 expected mutating route family: ' . $family); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14DataLifecycleArchivePurgeContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14DataLifecycleArchivePurgeContractTest.php index db86628b..825ff17a 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14DataLifecycleArchivePurgeContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14DataLifecycleArchivePurgeContractTest.php @@ -6,15 +6,14 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14DataLifecycleArchivePurgeContractTest extends FullSurfaceE2EContractCase { - public function test_archive_purge_and_retention_routes_require_safe_controlled_requests(): void +public function test_archive_purge_and_retention_routes_require_safe_controlled_requests(): void { foreach (array_slice($this->apiRoutesContainingAny(['archive', 'restore', 'purge', 'erase', 'retention', 'delete', 'destroy']), 0, 50) as $route) { $method = $this->primaryMethod($route); $response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $this->payloadFor($method, $route->uri()) + ['ids' => [$this->ids['studentId'], 99999999, '../../.env'], 'hard_delete' => true, 'purge' => true, 'cascade' => true, 'include_audit_logs' => true, 'reason' => '', 'confirmed' => false]); $this->assertControlled($response, $method, $route->uri()); $body = strtolower($response->getContent()); - $this->assertStringNotContainsString('sqlstate', $body); - $this->assertStringNotContainsString('foreign key constraint', $body); + $this->assertStringNotContainsString('sqlstate', $body); $this->assertStringNotContainsString('foreign key constraint', $body); } } @@ -22,12 +21,10 @@ class ApiBatch14DataLifecycleArchivePurgeContractTest extends FullSurfaceE2ECont { foreach (array_slice($this->apiRoutesContainingAny(['purge', 'erase', 'restore', 'archive', 'delete']), 0, 35) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { - continue; - } + if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; } foreach ([$this->teacher, $this->parent, $this->studentUser] as $actor) { $response = $this->requestAs($actor, $method, $route->uri(), ['ids' => [$this->ids['studentId']], 'hard_delete' => true, 'purge' => true, 'global' => true]); - $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri()); + $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri()); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14FinanceReconciliationAndRefundAbuseContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14FinanceReconciliationAndRefundAbuseContractTest.php index a96f3b74..c83be0f7 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14FinanceReconciliationAndRefundAbuseContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14FinanceReconciliationAndRefundAbuseContractTest.php @@ -6,18 +6,16 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14FinanceReconciliationAndRefundAbuseContractTest extends FullSurfaceE2EContractCase { - public function test_finance_reconciliation_routes_reject_mismatched_invoice_parent_and_payment_fields(): void +public function test_finance_reconciliation_routes_reject_mismatched_invoice_parent_and_payment_fields(): void { foreach (array_slice($this->apiRoutesContainingAny(['finance', 'invoice', 'payment', 'refund', 'transaction', 'ledger', 'reconcile']), 0, 55) as $route) { $method = $this->primaryMethod($route); $response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $this->payloadFor($method, $route->uri()) + [ - 'invoice_id' => $this->ids['invoiceId'], 'parent_id' => 99999999, 'student_id' => 99999999, 'payment_id' => 99999999, 'refund_id' => 99999999, 'transaction_id' => 'provider-'.uniqid(), 'provider_transaction_id' => 'provider-'.uniqid(), 'amount' => -99999.99, 'net_amount' => -99999.99, 'fee_amount' => -99999.99, 'currency' => 'XXX', 'reconciled' => true, 'force_posted' => true, + 'invoice_id' => $this->ids['invoiceId'], 'parent_id' => 99999999, 'student_id' => 99999999, 'payment_id' => 99999999, 'refund_id' => 99999999, 'transaction_id' => 'provider-' . uniqid(), 'provider_transaction_id' => 'provider-' . uniqid(), 'amount' => -99999.99, 'net_amount' => -99999.99, 'fee_amount' => -99999.99, 'currency' => 'XXX', 'reconciled' => true, 'force_posted' => true, ]); $this->assertControlled($response, $method, $route->uri()); $body = strtolower($response->getContent()); - $this->assertStringNotContainsString('sqlstate', $body); - $this->assertStringNotContainsString('duplicate entry', $body); - $this->assertStringNotContainsString('foreign key constraint', $body); + $this->assertStringNotContainsString('sqlstate', $body); $this->assertStringNotContainsString('duplicate entry', $body); $this->assertStringNotContainsString('foreign key constraint', $body); } } @@ -25,11 +23,9 @@ class ApiBatch14FinanceReconciliationAndRefundAbuseContractTest extends FullSurf { foreach (array_slice($this->apiRoutesContainingAny(['refund', 'reconcile', 'ledger', 'payment']), 0, 35) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { - continue; - } + if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; } $response = $this->requestAs($this->parent, $method, $route->uri(), ['invoice_id' => $this->ids['invoiceId'], 'amount' => 100.00, 'approved' => true, 'reconciled' => true, 'refund_now' => true]); - $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri()); + $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri()); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14NotificationTemplateInjectionContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14NotificationTemplateInjectionContractTest.php index 7546f928..3c4dede5 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14NotificationTemplateInjectionContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14NotificationTemplateInjectionContractTest.php @@ -6,21 +6,17 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14NotificationTemplateInjectionContractTest extends FullSurfaceE2EContractCase { - public function test_notification_and_template_routes_reject_template_injection_payloads(): void +public function test_notification_and_template_routes_reject_template_injection_payloads(): void { foreach (array_slice($this->apiRoutesContainingAny(['notification', 'notify', 'message', 'email', 'whatsapp', 'template', 'broadcast']), 0, 55) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { - continue; - } + if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { continue; } $response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $this->payloadFor($method, $route->uri()) + [ 'subject' => '{{ config("app.key") }}', 'message' => '{{ $user->password }}', 'body' => '${jndi:ldap://127.0.0.1/a}', 'template' => '@php echo env("APP_KEY"); @endphp', 'channel' => 'all', 'recipients' => ['*'], 'phone' => "+15551234567\r\nBcc: attacker@example.test", 'email' => "victim@example.test\r\nBcc: attacker@example.test", ]); $this->assertControlled($response, $method, $route->uri()); $body = strtolower($response->getContent()); - $this->assertStringNotContainsString('app_key', $body); - $this->assertStringNotContainsString('document.cookie', $body); - $this->assertStringNotContainsString('jndi:ldap', $body); + $this->assertStringNotContainsString('app_key', $body); $this->assertStringNotContainsString('document.cookie', $body); $this->assertStringNotContainsString('jndi:ldap', $body); } } @@ -28,12 +24,10 @@ class ApiBatch14NotificationTemplateInjectionContractTest extends FullSurfaceE2E { foreach (array_slice($this->apiRoutesContainingAny(['broadcast', 'notification', 'email', 'whatsapp']), 0, 30) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { - continue; - } + if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { continue; } foreach ([$this->parent, $this->teacher, $this->studentUser] as $actor) { $response = $this->requestAs($actor, $method, $route->uri(), ['channel' => 'all', 'recipients' => ['all_school'], 'template_id' => 1, 'force_send' => true]); - $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri()); + $this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri()); } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14PrintExportTamperingContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14PrintExportTamperingContractTest.php index 32552660..6be2e9a7 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14PrintExportTamperingContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14PrintExportTamperingContractTest.php @@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14PrintExportTamperingContractTest extends FullSurfaceE2EContractCase { - public function test_print_export_and_document_generation_routes_reject_tampered_scope_fields(): void +public function test_print_export_and_document_generation_routes_reject_tampered_scope_fields(): void { foreach (array_slice($this->apiRoutesContainingAny(['print', 'export', 'download', 'certificate', 'badge', 'receipt', 'transcript', 'report-card']), 0, 50) as $route) { $method = $this->primaryMethod($route); @@ -15,9 +15,7 @@ class ApiBatch14PrintExportTamperingContractTest extends FullSurfaceE2EContractC ]); $this->assertControlled($response, $method, $route->uri()); $body = strtolower($response->getContent()); - foreach (['app_key', 'laravel.log', 'password', 'remember_token', 'sqlstate'] as $forbidden) { - $this->assertStringNotContainsString($forbidden, $body); - } + foreach (['app_key', 'laravel.log', 'password', 'remember_token', 'sqlstate'] as $forbidden) { $this->assertStringNotContainsString($forbidden, $body); } } } @@ -27,7 +25,7 @@ class ApiBatch14PrintExportTamperingContractTest extends FullSurfaceE2EContractC $method = $this->primaryMethod($route); foreach ([$this->parent, $this->teacher, $this->studentUser] as $actor) { $response = $this->requestAs($actor, $method, $route->uri(), ['scope' => 'all_school', 'all_students' => true, 'include_finance' => true, 'include_guardians' => true, 'format' => 'csv']); - $this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri()); + $this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri()); $this->assertStringNotContainsString('remember_token', strtolower($response->getContent())); } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14RegressionMegaSweepTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14RegressionMegaSweepTest.php index 3a7f2415..33cb73da 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14RegressionMegaSweepTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14RegressionMegaSweepTest.php @@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14RegressionMegaSweepTest extends FullSurfaceE2EContractCase { - public function test_batch14_mega_sweep_keeps_new_risk_payloads_under_controlled_failure(): void +public function test_batch14_mega_sweep_keeps_new_risk_payloads_under_controlled_failure(): void { $families = [ ['auth', 'login', 'password', 'verify'], ['users', 'roles', 'permissions', 'profile'], ['students', 'parents', 'family', 'guardian'], @@ -26,9 +26,7 @@ class ApiBatch14RegressionMegaSweepTest extends FullSurfaceE2EContractCase $response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $payload); $this->assertControlled($response, $method, $route->uri()); $body = strtolower($response->getContent()); - foreach (['sqlstate', 'app_key', 'db_password', 'remember_token', 'stack trace', 'laravel.log'] as $forbidden) { - $this->assertStringNotContainsString($forbidden, $body); - } + foreach (['sqlstate', 'app_key', 'db_password', 'remember_token', 'stack trace', 'laravel.log'] as $forbidden) { $this->assertStringNotContainsString($forbidden, $body); } } } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14RelationshipOwnershipMatrixExpansionTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14RelationshipOwnershipMatrixExpansionTest.php index b4f81e04..2c12014a 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14RelationshipOwnershipMatrixExpansionTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14RelationshipOwnershipMatrixExpansionTest.php @@ -6,19 +6,15 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14RelationshipOwnershipMatrixExpansionTest extends FullSurfaceE2EContractCase { - public function test_relationship_owner_override_fields_are_not_trusted_across_route_families(): void +public function test_relationship_owner_override_fields_are_not_trusted_across_route_families(): void { foreach (array_slice($this->apiRoutesContainingAny(['student', 'parent', 'family', 'invoice', 'attendance', 'score', 'guardian', 'authorized']), 0, 60) as $route) { $method = $this->primaryMethod($route); - if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { - continue; - } + if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; } foreach ([$this->parent, $this->teacher] as $actor) { $response = $this->requestAs($actor, $method, $route->uri(), $this->payloadFor($method, $route->uri()) + ['student_ids' => [$this->ids['studentId'], 99999999], 'parent_id' => 99999999, 'family_id' => 99999999, 'guardian_id' => 99999999, 'owner_id' => $this->admin->id, 'owner_type' => 'App\\Models\\User', 'created_by' => $this->admin->id, 'scope' => 'global']); $this->assertControlled($response, $method, $route->uri()); - $body = strtolower($response->getContent()); - $this->assertStringNotContainsString('sqlstate', $body); - $this->assertStringNotContainsString('remember_token', $body); + $body = strtolower($response->getContent()); $this->assertStringNotContainsString('sqlstate', $body); $this->assertStringNotContainsString('remember_token', $body); } } } @@ -28,7 +24,7 @@ class ApiBatch14RelationshipOwnershipMatrixExpansionTest extends FullSurfaceE2EC foreach (array_slice($this->apiRoutesContainingAny(['parent', 'family', 'guardian', 'invoice', 'attendance', 'report-card']), 0, 40) as $route) { $method = $this->primaryMethod($route); $response = $this->requestAs($this->studentUser, $method, $route->uri(), ['student_id' => 99999999, 'parent_id' => 99999999, 'family_id' => 99999999, 'include' => 'guardians,invoices,attendance,notes']); - $this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri()); + $this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri()); $this->assertStringNotContainsString('remember_token', strtolower($response->getContent())); } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14SessionCookieCsrfBoundaryContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14SessionCookieCsrfBoundaryContractTest.php index 6a7a1c45..2073b4dc 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14SessionCookieCsrfBoundaryContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14SessionCookieCsrfBoundaryContractTest.php @@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14SessionCookieCsrfBoundaryContractTest extends FullSurfaceE2EContractCase { - public function test_api_auth_routes_do_not_depend_on_browser_session_cookies(): void +public function test_api_auth_routes_do_not_depend_on_browser_session_cookies(): void { foreach (array_slice($this->apiRoutesContainingAny(['auth', 'login', 'logout', 'me', 'profile', 'frontend']), 0, 40) as $route) { $method = $this->primaryMethod($route); @@ -26,7 +26,7 @@ class ApiBatch14SessionCookieCsrfBoundaryContractTest extends FullSurfaceE2ECont $response = $this->withCookie('laravel_session', 'fake-admin-browser-session') ->withHeaders(['X-Requested-With' => 'XMLHttpRequest', 'X-CSRF-TOKEN' => 'fake-csrf', 'X-User-Id' => (string) $this->admin->id]) ->json($method, $this->materializePath($route->uri()), $this->payloadFor($method, $route->uri())); - $this->assertStatusIn($response, [401, 403, 404, 405, 419, 422], $method.' '.$route->uri()); + $this->assertStatusIn($response, [401, 403, 404, 405, 419, 422], $method . ' ' . $route->uri()); $this->assertStringNotContainsString('sqlstate', strtolower($response->getContent())); } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch14StoragePathAndSignedUrlContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch14StoragePathAndSignedUrlContractTest.php index b925e4a1..ce080f4f 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch14StoragePathAndSignedUrlContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch14StoragePathAndSignedUrlContractTest.php @@ -6,16 +6,14 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch14StoragePathAndSignedUrlContractTest extends FullSurfaceE2EContractCase { - public function test_file_and_signed_url_routes_reject_path_and_disk_overrides(): void +public function test_file_and_signed_url_routes_reject_path_and_disk_overrides(): void { foreach (array_slice($this->apiRoutesContainingAny(['file', 'media', 'upload', 'download', 'export', 'import', 'attachment', 'document', 'signed']), 0, 55) as $route) { $method = $this->primaryMethod($route); $response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $this->payloadFor($method, $route->uri()) + ['path' => '../../.env', 'filename' => '../../storage/logs/laravel.log', 'disk' => 'local', 'storage_disk' => 's3://private-bucket', 'url' => 'file:///etc/passwd', 'expires' => '2099-01-01', 'signature' => 'forged-signature', 'mime_type' => 'text/x-php']); $this->assertControlled($response, $method, $route->uri()); $body = strtolower($response->getContent()); - foreach (['app_key', 'db_password', 'laravel.log', '/etc/passwd', 'begin rsa private key'] as $forbidden) { - $this->assertStringNotContainsString($forbidden, $body); - } + foreach (['app_key', 'db_password', 'laravel.log', '/etc/passwd', 'begin rsa private key'] as $forbidden) { $this->assertStringNotContainsString($forbidden, $body); } } } @@ -23,8 +21,8 @@ class ApiBatch14StoragePathAndSignedUrlContractTest extends FullSurfaceE2EContra { foreach (array_slice($this->apiRoutesContainingAny(['download', 'signed', 'public', 'media', 'file']), 0, 35) as $route) { $method = $this->primaryMethod($route); - $response = $this->json($method, $this->materializePath($route->uri()).'?signature=forged&expires=1&path=../../.env'); - $this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 410, 419, 422], $method.' '.$route->uri()); + $response = $this->json($method, $this->materializePath($route->uri()) . '?signature=forged&expires=1&path=../../.env'); + $this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 410, 419, 422], $method . ' ' . $route->uri()); $this->assertStringNotContainsString('app_key', strtolower($response->getContent())); } } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15AdminImpersonationSessionBoundaryContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15AdminImpersonationSessionBoundaryContractTest.php index 41b7118d..adc9fc2b 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15AdminImpersonationSessionBoundaryContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15AdminImpersonationSessionBoundaryContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15AdminImpersonationSessionBoundaryContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_impersonation_and_acting_as_routes_require_real_admin_context_not_payload_claims(): void { $routes = $this->apiRoutesContainingAny(['impersonate', 'acting-as', 'act-as', 'switch-user', 'delegate', 'behalf']); @@ -27,4 +28,5 @@ class ApiBatch15AdminImpersonationSessionBoundaryContractTest extends FullSurfac $this->assertStringNotContainsString('access_token', strtolower($parentResponse->getContent())); } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15AuthTokenRotationAndRevocationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15AuthTokenRotationAndRevocationContractTest.php index e770e195..eed4e194 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15AuthTokenRotationAndRevocationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15AuthTokenRotationAndRevocationContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15AuthTokenRotationAndRevocationContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_token_rotation_revocation_and_identity_routes_do_not_accept_stale_or_forged_tokens(): void { $routes = $this->apiRoutesContainingAny(['auth', 'login', 'logout', 'refresh', 'token', 'me', 'profile', 'session']); @@ -45,4 +46,5 @@ class ApiBatch15AuthTokenRotationAndRevocationContractTest extends FullSurfaceE2 } } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15BackgroundCommandAndSchedulerContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15BackgroundCommandAndSchedulerContractTest.php index 37e0d85b..f45d2915 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15BackgroundCommandAndSchedulerContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15BackgroundCommandAndSchedulerContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15BackgroundCommandAndSchedulerContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_command_scheduler_and_job_trigger_routes_are_admin_only_and_idempotent(): void { $routes = $this->apiRoutesContainingAny(['command', 'schedule', 'scheduler', 'cron', 'job', 'queue', 'sync', 'recalculate', 'cleanup', 'send']); @@ -29,4 +30,5 @@ class ApiBatch15BackgroundCommandAndSchedulerContractTest extends FullSurfaceE2E $this->assertControlled($adminResponse, $method, $uri); } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15ConsentPrivacyAndDataSubjectRightsContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15ConsentPrivacyAndDataSubjectRightsContractTest.php index 90315bc5..9d18ee5d 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15ConsentPrivacyAndDataSubjectRightsContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15ConsentPrivacyAndDataSubjectRightsContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15ConsentPrivacyAndDataSubjectRightsContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_privacy_consent_erasure_and_export_routes_are_admin_or_owner_scoped(): void { $routes = $this->apiRoutesContainingAny(['privacy', 'consent', 'erase', 'erasure', 'delete-account', 'export-data', 'data-subject', 'retention']); @@ -43,4 +44,5 @@ class ApiBatch15ConsentPrivacyAndDataSubjectRightsContractTest extends FullSurfa $this->assertStringNotContainsString('db_password', strtolower($response->getContent())); } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15CrossSchoolIdentityCollisionContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15CrossSchoolIdentityCollisionContractTest.php index 3e4cb03c..c9c1c5bd 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15CrossSchoolIdentityCollisionContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15CrossSchoolIdentityCollisionContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15CrossSchoolIdentityCollisionContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_duplicate_external_identifiers_and_cross_school_aliases_fail_cleanly(): void { $routes = $this->apiRoutesContainingAny(['students', 'users', 'parents', 'family', 'guardian', 'enrollment', 'registration']); @@ -30,4 +31,5 @@ class ApiBatch15CrossSchoolIdentityCollisionContractTest extends FullSurfaceE2EC $this->assertStringNotContainsString('duplicate entry', strtolower($response->getContent())); } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15DataResidencyBackupAndRestoreContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15DataResidencyBackupAndRestoreContractTest.php index f86d06ab..c1680cbe 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15DataResidencyBackupAndRestoreContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15DataResidencyBackupAndRestoreContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15DataResidencyBackupAndRestoreContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_backup_restore_residency_and_snapshot_routes_do_not_expose_or_mutate_for_low_privilege_users(): void { $routes = $this->apiRoutesContainingAny(['backup', 'restore', 'snapshot', 'residency', 'tenant', 'database', 'dump', 'archive']); @@ -31,4 +32,5 @@ class ApiBatch15DataResidencyBackupAndRestoreContractTest extends FullSurfaceE2E } } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15DomainEventOutboxAndNotificationConsistencyContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15DomainEventOutboxAndNotificationConsistencyContractTest.php index 0f7b2b7e..f27096a8 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15DomainEventOutboxAndNotificationConsistencyContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15DomainEventOutboxAndNotificationConsistencyContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15DomainEventOutboxAndNotificationConsistencyContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_event_outbox_and_notification_trigger_routes_reject_forged_event_metadata(): void { $routes = $this->apiRoutesContainingAny(['event', 'outbox', 'notification', 'broadcast', 'message', 'email', 'whatsapp', 'webhook']); @@ -27,4 +28,5 @@ class ApiBatch15DomainEventOutboxAndNotificationConsistencyContractTest extends $this->assertControlled($response, $method, $uri); } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15FeatureFlagExperimentAndRolloutContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15FeatureFlagExperimentAndRolloutContractTest.php index e3aaa287..90b1e66c 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15FeatureFlagExperimentAndRolloutContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15FeatureFlagExperimentAndRolloutContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15FeatureFlagExperimentAndRolloutContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_feature_flag_and_rollout_routes_reject_low_privilege_override_payloads(): void { $routes = $this->apiRoutesContainingAny(['feature', 'flag', 'experiment', 'rollout', 'settings', 'configuration']); @@ -27,4 +28,5 @@ class ApiBatch15FeatureFlagExperimentAndRolloutContractTest extends FullSurfaceE $this->assertControlled($response, $method, $uri); } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15FormRequestAuthorizationCoverageContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15FormRequestAuthorizationCoverageContractTest.php index 6882af99..4eac3aa3 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15FormRequestAuthorizationCoverageContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15FormRequestAuthorizationCoverageContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15FormRequestAuthorizationCoverageContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_mutating_routes_do_not_allow_public_or_low_privilege_form_request_bypass(): void { foreach (array_slice($this->apiRoutes(), 0, 120) as $route) { @@ -28,4 +29,5 @@ class ApiBatch15FormRequestAuthorizationCoverageContractTest extends FullSurface $this->assertControlled($response, $method, $uri); } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15GlobalSearchAndDirectoryEnumerationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15GlobalSearchAndDirectoryEnumerationContractTest.php index 8025c9ec..dc5b1331 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15GlobalSearchAndDirectoryEnumerationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15GlobalSearchAndDirectoryEnumerationContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15GlobalSearchAndDirectoryEnumerationContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_global_search_directory_and_lookup_routes_resist_enumeration_inputs(): void { $routes = $this->apiRoutesContainingAny(['search', 'lookup', 'directory', 'autocomplete', 'users', 'students', 'parents']); @@ -26,4 +27,5 @@ class ApiBatch15GlobalSearchAndDirectoryEnumerationContractTest extends FullSurf } } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15LocalizationContentDirectionAndEncodingContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15LocalizationContentDirectionAndEncodingContractTest.php index 3035cbfa..50580682 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15LocalizationContentDirectionAndEncodingContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15LocalizationContentDirectionAndEncodingContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15LocalizationContentDirectionAndEncodingContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_rtl_unicode_and_encoding_payloads_remain_controlled_across_text_routes(): void { $routes = $this->apiRoutesContainingAny(['message', 'contact', 'support', 'notification', 'student', 'parent', 'settings', 'certificate']); @@ -30,4 +31,5 @@ class ApiBatch15LocalizationContentDirectionAndEncodingContractTest extends Full $this->assertStringNotContainsString('malformed utf-8', strtolower($response->getContent())); } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15MetadataFilteringAndSparseFieldsetSecurityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15MetadataFilteringAndSparseFieldsetSecurityContractTest.php index 906c5aca..5ff26a3b 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15MetadataFilteringAndSparseFieldsetSecurityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15MetadataFilteringAndSparseFieldsetSecurityContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15MetadataFilteringAndSparseFieldsetSecurityContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_sparse_fieldsets_metadata_and_embeds_do_not_reveal_sensitive_associations(): void { $routes = $this->apiRoutesContainingAny(['users', 'students', 'parents', 'family', 'finance', 'attendance', 'reports', 'dashboard']); @@ -30,4 +31,5 @@ class ApiBatch15MetadataFilteringAndSparseFieldsetSecurityContractTest extends F } } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15RateLimitAndAbusePatternContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15RateLimitAndAbusePatternContractTest.php index 3a7c7c74..11d8f6a4 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15RateLimitAndAbusePatternContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15RateLimitAndAbusePatternContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15RateLimitAndAbusePatternContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_repeated_sensitive_requests_return_controlled_responses_without_leaking_internals(): void { $routes = $this->apiRoutesContainingAny(['login', 'password', 'verify', 'contact', 'support', 'message', 'scanner', 'badge']); @@ -15,7 +16,7 @@ class ApiBatch15RateLimitAndAbusePatternContractTest extends FullSurfaceE2EContr $uri = $route->uri(); for ($attempt = 1; $attempt <= 3; $attempt++) { - $response = $this->withHeader('X-Forwarded-For', '203.0.113.'.$attempt) + $response = $this->withHeader('X-Forwarded-For', '203.0.113.' . $attempt) ->requestAs($this->actorFor($uri), $method, $uri, $this->payloadFor($method, $uri) + [ 'email' => 'rate-limit-'.$attempt.'@example.test', 'password' => 'wrong-password', @@ -30,4 +31,5 @@ class ApiBatch15RateLimitAndAbusePatternContractTest extends FullSurfaceE2EContr } } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15RegressionUltraSweepTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15RegressionUltraSweepTest.php index 79ee779c..c81337be 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15RegressionUltraSweepTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15RegressionUltraSweepTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15RegressionUltraSweepTest extends FullSurfaceE2EContractCase { + public function test_batch15_ultra_sweep_keeps_cross_domain_hostile_payloads_under_controlled_responses(): void { $families = [ @@ -42,4 +43,5 @@ class ApiBatch15RegressionUltraSweepTest extends FullSurfaceE2EContractCase } } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15ReportDrilldownAndAggregatePrivacyContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15ReportDrilldownAndAggregatePrivacyContractTest.php index 3ab667b2..afdb971a 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15ReportDrilldownAndAggregatePrivacyContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15ReportDrilldownAndAggregatePrivacyContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15ReportDrilldownAndAggregatePrivacyContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_report_drilldown_filters_do_not_allow_scope_escape_or_sensitive_field_inclusion(): void { $routes = $this->apiRoutesContainingAny(['report', 'analytics', 'dashboard', 'summary', 'drilldown', 'export']); @@ -33,4 +34,5 @@ class ApiBatch15ReportDrilldownAndAggregatePrivacyContractTest extends FullSurfa } } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15RouteParameterPoisoningExpansionTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15RouteParameterPoisoningExpansionTest.php index 113e109a..0b9ffed2 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15RouteParameterPoisoningExpansionTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15RouteParameterPoisoningExpansionTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15RouteParameterPoisoningExpansionTest extends FullSurfaceE2EContractCase { + public function test_batch15_route_parameters_reject_encoded_path_script_and_type_confusion_payloads_cleanly(): void { $poisoned = ['..%2F..%2F.env', '%00', '', '1 or 1=1', str_repeat('9', 80), '٠١٢٣', 'null', '[]']; @@ -17,7 +18,7 @@ class ApiBatch15RouteParameterPoisoningExpansionTest extends FullSurfaceE2EContr $method = $this->primaryMethod($route); foreach (array_slice($poisoned, 0, 4) as $value) { - $path = '/'.preg_replace('/\{[^}]+\}/', $value, $route->uri()); + $path = '/' . preg_replace('/\{[^}]+\}/', $value, $route->uri()); $this->actingAs($this->actorFor($route->uri()), 'api'); $response = $this->json($method, $path, $this->payloadFor($method, $route->uri())); $this->assertControlled($response, $method, $route->uri()); @@ -25,4 +26,5 @@ class ApiBatch15RouteParameterPoisoningExpansionTest extends FullSurfaceE2EContr } } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch15StudentSafetyIncidentEscalationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch15StudentSafetyIncidentEscalationContractTest.php index fe7ee79c..390e3284 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch15StudentSafetyIncidentEscalationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch15StudentSafetyIncidentEscalationContractTest.php @@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; class ApiBatch15StudentSafetyIncidentEscalationContractTest extends FullSurfaceE2EContractCase { + public function test_batch15_safety_incident_escalation_routes_are_not_mutable_by_parents_or_students(): void { $routes = $this->apiRoutesContainingAny(['incident', 'violation', 'safety', 'alert', 'flag', 'dismissal', 'late', 'absence', 'attendance']); @@ -28,4 +29,5 @@ class ApiBatch15StudentSafetyIncidentEscalationContractTest extends FullSurfaceE } } } + } diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17AcademicPrerequisiteAndDependencyContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17AcademicPrerequisiteAndDependencyContractTest.php index a43f9cb2..8d3041fd 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17AcademicPrerequisiteAndDependencyContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17AcademicPrerequisiteAndDependencyContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17AcademicPrerequisiteAndDependencyContractTest extends FullSurfaceE2EContractCase { public function test_academic_actions_do_not_skip_required_prerequisites_or_locks(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17ApiContractDiffAndCriticalKeyRegisterTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17ApiContractDiffAndCriticalKeyRegisterTest.php index 367cce78..3b302de2 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17ApiContractDiffAndCriticalKeyRegisterTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17ApiContractDiffAndCriticalKeyRegisterTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17ApiContractDiffAndCriticalKeyRegisterTest extends FullSurfaceE2EContractCase { public function test_critical_identity_finance_attendance_and_academic_payloads_keep_contract_anchors(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17AttendanceTamperWindowContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17AttendanceTamperWindowContractTest.php index 310e4209..ed581198 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17AttendanceTamperWindowContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17AttendanceTamperWindowContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17AttendanceTamperWindowContractTest extends FullSurfaceE2EContractCase { public function test_attendance_cutoff_backdate_future_and_reason_requirements_are_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17CommunicationRecipientExpansionContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17CommunicationRecipientExpansionContractTest.php index d8c90dea..9161b259 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17CommunicationRecipientExpansionContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17CommunicationRecipientExpansionContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17CommunicationRecipientExpansionContractTest extends FullSurfaceE2EContractCase { public function test_message_broadcast_and_notification_recipient_scope_cannot_be_expanded_by_payload(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17DataLineageAndSourceAttributionContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17DataLineageAndSourceAttributionContractTest.php index feaea17d..68d988da 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17DataLineageAndSourceAttributionContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17DataLineageAndSourceAttributionContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17DataLineageAndSourceAttributionContractTest extends FullSurfaceE2EContractCase { public function test_client_supplied_lineage_and_audit_source_fields_are_not_authoritative(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17ExportColumnLevelSecurityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17ExportColumnLevelSecurityContractTest.php index a42ee2d2..66fb484b 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17ExportColumnLevelSecurityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17ExportColumnLevelSecurityContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17ExportColumnLevelSecurityContractTest extends FullSurfaceE2EContractCase { public function test_export_field_selection_cannot_request_secrets_or_cross_scope_columns(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17ExternalIdAndNaturalKeyCollisionContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17ExternalIdAndNaturalKeyCollisionContractTest.php index 3917548a..604058ce 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17ExternalIdAndNaturalKeyCollisionContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17ExternalIdAndNaturalKeyCollisionContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17ExternalIdAndNaturalKeyCollisionContractTest extends FullSurfaceE2EContractCase { public function test_external_ids_student_numbers_and_emails_are_not_cross_domain_authority(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17FinancialPeriodCloseAndAdjustmentContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17FinancialPeriodCloseAndAdjustmentContractTest.php index f56b36b0..832ca735 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17FinancialPeriodCloseAndAdjustmentContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17FinancialPeriodCloseAndAdjustmentContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17FinancialPeriodCloseAndAdjustmentContractTest extends FullSurfaceE2EContractCase { public function test_closed_period_adjustments_writeoffs_and_credit_transfers_are_guarded(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17InventoryAssetCustodyContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17InventoryAssetCustodyContractTest.php index 1fc865aa..70c8db71 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17InventoryAssetCustodyContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17InventoryAssetCustodyContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17InventoryAssetCustodyContractTest extends FullSurfaceE2EContractCase { public function test_inventory_asset_custody_transfers_and_disposal_are_not_client_authorized(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17MultiGuardBoundaryContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17MultiGuardBoundaryContractTest.php index f9add2c4..dba62eb6 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17MultiGuardBoundaryContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17MultiGuardBoundaryContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17MultiGuardBoundaryContractTest extends FullSurfaceE2EContractCase { public function test_api_guard_boundaries_are_not_crossed_by_session_or_web_identity(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17PartialFailureErrorDetailRedactionContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17PartialFailureErrorDetailRedactionContractTest.php index 9d3ec409..6bf3f05b 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17PartialFailureErrorDetailRedactionContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17PartialFailureErrorDetailRedactionContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17PartialFailureErrorDetailRedactionContractTest extends FullSurfaceE2EContractCase { public function test_bulk_partial_failure_details_are_actionable_without_leaking_database_or_secret_details(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17PerResourceRateLimitIdentityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17PerResourceRateLimitIdentityContractTest.php index c00e1cbf..5b35561d 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17PerResourceRateLimitIdentityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17PerResourceRateLimitIdentityContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17PerResourceRateLimitIdentityContractTest extends FullSurfaceE2EContractCase { public function test_repeated_sensitive_actions_are_scoped_by_actor_resource_and_operation(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17RegressionOmegaSweepTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17RegressionOmegaSweepTest.php index 8208f7fc..06a72b3f 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17RegressionOmegaSweepTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17RegressionOmegaSweepTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17RegressionOmegaSweepTest extends FullSurfaceE2EContractCase { public function test_batch17_omega_sweep_combines_headers_payloads_queries_and_route_parameters(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17SearchRankingAndPermissionFilterContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17SearchRankingAndPermissionFilterContractTest.php index 412cf0aa..e0683e5f 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17SearchRankingAndPermissionFilterContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17SearchRankingAndPermissionFilterContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17SearchRankingAndPermissionFilterContractTest extends FullSurfaceE2EContractCase { public function test_search_autocomplete_and_lookup_do_not_bypass_permission_filters(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17StudentIdentityMergeSplitContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17StudentIdentityMergeSplitContractTest.php index ed8dd426..d564a982 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17StudentIdentityMergeSplitContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17StudentIdentityMergeSplitContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17StudentIdentityMergeSplitContractTest extends FullSurfaceE2EContractCase { public function test_merge_split_and_duplicate_student_identity_routes_reject_unsafe_payloads(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch17ZeroTrustInternalHeaderContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch17ZeroTrustInternalHeaderContractTest.php index a68dab8a..6b6f30ab 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch17ZeroTrustInternalHeaderContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch17ZeroTrustInternalHeaderContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch17ZeroTrustInternalHeaderContractTest extends FullSurfaceE2EContractCase { public function test_internal_proxy_and_service_headers_do_not_grant_privilege(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18ApiKeyServiceAccountAndMachineIdentityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18ApiKeyServiceAccountAndMachineIdentityContractTest.php index 6028a31a..3e083430 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18ApiKeyServiceAccountAndMachineIdentityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18ApiKeyServiceAccountAndMachineIdentityContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18ApiKeyServiceAccountAndMachineIdentityContractTest extends FullSurfaceE2EContractCase { public function test_batch18_apikeyserviceaccountandmachineidentity_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18CanonicalIdentifierImmutabilityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18CanonicalIdentifierImmutabilityContractTest.php index 36e7ce0e..ffeef331 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18CanonicalIdentifierImmutabilityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18CanonicalIdentifierImmutabilityContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18CanonicalIdentifierImmutabilityContractTest extends FullSurfaceE2EContractCase { public function test_batch18_canonicalidentifierimmutability_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18ClassCapacityWaitlistAndScheduleConflictContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18ClassCapacityWaitlistAndScheduleConflictContractTest.php index ad7554e1..8820229b 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18ClassCapacityWaitlistAndScheduleConflictContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18ClassCapacityWaitlistAndScheduleConflictContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18ClassCapacityWaitlistAndScheduleConflictContractTest extends FullSurfaceE2EContractCase { public function test_batch18_classcapacitywaitlistandscheduleconflict_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18ConsentRevocationAndCommunicationComplianceContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18ConsentRevocationAndCommunicationComplianceContractTest.php index 23a881f4..8d1bfdb4 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18ConsentRevocationAndCommunicationComplianceContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18ConsentRevocationAndCommunicationComplianceContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18ConsentRevocationAndCommunicationComplianceContractTest extends FullSurfaceE2EContractCase { public function test_batch18_consentrevocationandcommunicationcompliance_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18CrossModuleBusinessInvariantRegisterTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18CrossModuleBusinessInvariantRegisterTest.php index 3425d02b..eff26c3d 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18CrossModuleBusinessInvariantRegisterTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18CrossModuleBusinessInvariantRegisterTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18CrossModuleBusinessInvariantRegisterTest extends FullSurfaceE2EContractCase { public function test_batch18_business_invariant_route_families_remain_present(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18ExportWatermarkAndAuditabilityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18ExportWatermarkAndAuditabilityContractTest.php index ca413d4d..d427bfe3 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18ExportWatermarkAndAuditabilityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18ExportWatermarkAndAuditabilityContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18ExportWatermarkAndAuditabilityContractTest extends FullSurfaceE2EContractCase { public function test_batch18_exportwatermarkandauditability_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18FeatureEntitlementAndLicenseBoundaryContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18FeatureEntitlementAndLicenseBoundaryContractTest.php index 6de1c613..635c1f65 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18FeatureEntitlementAndLicenseBoundaryContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18FeatureEntitlementAndLicenseBoundaryContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18FeatureEntitlementAndLicenseBoundaryContractTest extends FullSurfaceE2EContractCase { public function test_batch18_featureentitlementandlicenseboundary_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18FileVirusScanAndQuarantineContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18FileVirusScanAndQuarantineContractTest.php index 1658af58..e2168257 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18FileVirusScanAndQuarantineContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18FileVirusScanAndQuarantineContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18FileVirusScanAndQuarantineContractTest extends FullSurfaceE2EContractCase { public function test_batch18_filevirusscanandquarantine_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18FinanceChargebackDisputeContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18FinanceChargebackDisputeContractTest.php index c4fa4962..916498ae 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18FinanceChargebackDisputeContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18FinanceChargebackDisputeContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18FinanceChargebackDisputeContractTest extends FullSurfaceE2EContractCase { public function test_batch18_financechargebackdispute_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18OrphanedRecordAndCascadeBoundaryContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18OrphanedRecordAndCascadeBoundaryContractTest.php index 89e3f6d0..0346ccbb 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18OrphanedRecordAndCascadeBoundaryContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18OrphanedRecordAndCascadeBoundaryContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18OrphanedRecordAndCascadeBoundaryContractTest extends FullSurfaceE2EContractCase { public function test_batch18_orphanedrecordandcascadeboundary_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18PrivilegeBoundaryAfterRoleMutationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18PrivilegeBoundaryAfterRoleMutationContractTest.php index 1fb1388f..de26f526 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18PrivilegeBoundaryAfterRoleMutationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18PrivilegeBoundaryAfterRoleMutationContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18PrivilegeBoundaryAfterRoleMutationContractTest extends FullSurfaceE2EContractCase { public function test_batch18_privilegeboundaryafterrolemutation_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18RegressionFinalitySweepTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18RegressionFinalitySweepTest.php index b7f1bd47..e63327f3 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18RegressionFinalitySweepTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18RegressionFinalitySweepTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18RegressionFinalitySweepTest extends FullSurfaceE2EContractCase { public function test_batch18_combined_hostile_payload_sweep_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18ReportDrillthroughAndRowLevelSecurityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18ReportDrillthroughAndRowLevelSecurityContractTest.php index 5023a51a..9a01ac71 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18ReportDrillthroughAndRowLevelSecurityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18ReportDrillthroughAndRowLevelSecurityContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18ReportDrillthroughAndRowLevelSecurityContractTest extends FullSurfaceE2EContractCase { public function test_batch18_reportdrillthroughandrowlevelsecurity_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18StudentMedicalAndSafetyDataMinimizationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18StudentMedicalAndSafetyDataMinimizationContractTest.php index 8df5684a..555f1961 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18StudentMedicalAndSafetyDataMinimizationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18StudentMedicalAndSafetyDataMinimizationContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18StudentMedicalAndSafetyDataMinimizationContractTest extends FullSurfaceE2EContractCase { public function test_batch18_studentmedicalandsafetydataminimization_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18TemporalAuditAndTimezoneForgeryContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18TemporalAuditAndTimezoneForgeryContractTest.php index 1ad161ab..606e560f 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18TemporalAuditAndTimezoneForgeryContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18TemporalAuditAndTimezoneForgeryContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18TemporalAuditAndTimezoneForgeryContractTest extends FullSurfaceE2EContractCase { public function test_batch18_temporalauditandtimezoneforgery_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18TwoPersonApprovalAndSegregationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18TwoPersonApprovalAndSegregationContractTest.php index 6171148b..f4e7c064 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18TwoPersonApprovalAndSegregationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18TwoPersonApprovalAndSegregationContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18TwoPersonApprovalAndSegregationContractTest extends FullSurfaceE2EContractCase { public function test_batch18_twopersonapprovalandsegregation_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch18WebhookOrderingAndOutOfSequenceContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch18WebhookOrderingAndOutOfSequenceContractTest.php index b44e7702..d52c6050 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch18WebhookOrderingAndOutOfSequenceContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch18WebhookOrderingAndOutOfSequenceContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch18WebhookOrderingAndOutOfSequenceContractTest extends FullSurfaceE2EContractCase { public function test_batch18_webhookorderingandoutofsequence_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19AggregateDashboardScopeContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19AggregateDashboardScopeContractTest.php index c8331d4a..cecb1136 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19AggregateDashboardScopeContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19AggregateDashboardScopeContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19AggregateDashboardScopeContractTest extends FullSurfaceE2EContractCase { public function test_batch19_aggregate_dashboard_scope_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19AppendOnlyAuditLedgerContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19AppendOnlyAuditLedgerContractTest.php index e949c40d..1cb4a723 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19AppendOnlyAuditLedgerContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19AppendOnlyAuditLedgerContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19AppendOnlyAuditLedgerContractTest extends FullSurfaceE2EContractCase { public function test_batch19_append_only_audit_ledger_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19AttendanceExcuseDocumentLifecycleContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19AttendanceExcuseDocumentLifecycleContractTest.php index d2a664e0..aa433b98 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19AttendanceExcuseDocumentLifecycleContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19AttendanceExcuseDocumentLifecycleContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19AttendanceExcuseDocumentLifecycleContractTest extends FullSurfaceE2EContractCase { public function test_batch19_attendance_excuse_document_lifecycle_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19AttributeBasedAccessConditionContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19AttributeBasedAccessConditionContractTest.php index 1fa564dc..5661d445 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19AttributeBasedAccessConditionContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19AttributeBasedAccessConditionContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19AttributeBasedAccessConditionContractTest extends FullSurfaceE2EContractCase { public function test_batch19_attribute_based_access_condition_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19BackupRestoreIsolationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19BackupRestoreIsolationContractTest.php index 37843e1c..6e57b836 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19BackupRestoreIsolationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19BackupRestoreIsolationContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19BackupRestoreIsolationContractTest extends FullSurfaceE2EContractCase { public function test_batch19_backup_restore_isolation_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19ClassTransferTranscriptContinuityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19ClassTransferTranscriptContinuityContractTest.php index e4c1a9d8..806debf8 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19ClassTransferTranscriptContinuityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19ClassTransferTranscriptContinuityContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19ClassTransferTranscriptContinuityContractTest extends FullSurfaceE2EContractCase { public function test_batch19_class_transfer_transcript_continuity_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19CommunicationBounceAndSuppressionWebhookContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19CommunicationBounceAndSuppressionWebhookContractTest.php index e24080e2..92ed2541 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19CommunicationBounceAndSuppressionWebhookContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19CommunicationBounceAndSuppressionWebhookContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19CommunicationBounceAndSuppressionWebhookContractTest extends FullSurfaceE2EContractCase { public function test_batch19_communication_bounce_and_suppression_webhook_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19CustodyRestrictionPickupAuthorizationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19CustodyRestrictionPickupAuthorizationContractTest.php index b0635cd9..3e2b96bc 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19CustodyRestrictionPickupAuthorizationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19CustodyRestrictionPickupAuthorizationContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19CustodyRestrictionPickupAuthorizationContractTest extends FullSurfaceE2EContractCase { public function test_batch19_custody_restriction_pickup_authorization_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19NestedRelationshipRedactionContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19NestedRelationshipRedactionContractTest.php index ae7eedb2..27e97868 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19NestedRelationshipRedactionContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19NestedRelationshipRedactionContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19NestedRelationshipRedactionContractTest extends FullSurfaceE2EContractCase { public function test_batch19_nested_relationship_redaction_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19OperationalAndPrivacyInvariantRegisterTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19OperationalAndPrivacyInvariantRegisterTest.php index c717611a..001cfd57 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19OperationalAndPrivacyInvariantRegisterTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19OperationalAndPrivacyInvariantRegisterTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19OperationalAndPrivacyInvariantRegisterTest extends FullSurfaceE2EContractCase { public function test_batch19_operational_and_privacy_route_families_remain_present(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19PaymentAllocationAndBalanceContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19PaymentAllocationAndBalanceContractTest.php index bb82d802..dc498b1c 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19PaymentAllocationAndBalanceContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19PaymentAllocationAndBalanceContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19PaymentAllocationAndBalanceContractTest extends FullSurfaceE2EContractCase { public function test_batch19_payment_allocation_and_balance_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19RefundMethodAndSettlementBoundaryContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19RefundMethodAndSettlementBoundaryContractTest.php index c52b9d16..69c1774e 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19RefundMethodAndSettlementBoundaryContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19RefundMethodAndSettlementBoundaryContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19RefundMethodAndSettlementBoundaryContractTest extends FullSurfaceE2EContractCase { public function test_batch19_refund_method_and_settlement_boundary_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19RegressionContinuitySweepTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19RegressionContinuitySweepTest.php index b6902363..ceebf25b 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19RegressionContinuitySweepTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19RegressionContinuitySweepTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19RegressionContinuitySweepTest extends FullSurfaceE2EContractCase { public function test_batch19_continuity_and_privacy_sweep_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19ReportCacheInvalidationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19ReportCacheInvalidationContractTest.php index 898cf6bf..0ffa56a0 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19ReportCacheInvalidationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19ReportCacheInvalidationContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19ReportCacheInvalidationContractTest extends FullSurfaceE2EContractCase { public function test_batch19_report_cache_invalidation_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19RevokedDeletedUserTokenBoundaryContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19RevokedDeletedUserTokenBoundaryContractTest.php index 3d85a265..e6f17b69 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19RevokedDeletedUserTokenBoundaryContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19RevokedDeletedUserTokenBoundaryContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19RevokedDeletedUserTokenBoundaryContractTest extends FullSurfaceE2EContractCase { public function test_batch19_revoked_deleted_user_token_boundary_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19TeacherSubstitutionCoverageContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19TeacherSubstitutionCoverageContractTest.php index dafd1e84..3f9d029e 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19TeacherSubstitutionCoverageContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19TeacherSubstitutionCoverageContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19TeacherSubstitutionCoverageContractTest extends FullSurfaceE2EContractCase { public function test_batch19_teacher_substitution_coverage_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19TemporaryUrlExpirationRevocationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19TemporaryUrlExpirationRevocationContractTest.php index b1e13ac5..a148c868 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19TemporaryUrlExpirationRevocationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19TemporaryUrlExpirationRevocationContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19TemporaryUrlExpirationRevocationContractTest extends FullSurfaceE2EContractCase { public function test_batch19_temporary_url_expiration_revocation_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch19ThirdPartySyncCanonicalizationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch19ThirdPartySyncCanonicalizationContractTest.php index 78f7f3e4..7390fc20 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch19ThirdPartySyncCanonicalizationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch19ThirdPartySyncCanonicalizationContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch19ThirdPartySyncCanonicalizationContractTest extends FullSurfaceE2EContractCase { public function test_batch19_third_party_sync_canonicalization_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20AdminAuditExportRedactionContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20AdminAuditExportRedactionContractTest.php index 4a714112..8c936589 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20AdminAuditExportRedactionContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20AdminAuditExportRedactionContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20AdminAuditExportRedactionContractTest extends FullSurfaceE2EContractCase { public function test_batch20_admin_audit_export_redaction_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20ApiSunsetDeprecationAndCompatibilityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20ApiSunsetDeprecationAndCompatibilityContractTest.php index 4261a4d4..67fa59c7 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20ApiSunsetDeprecationAndCompatibilityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20ApiSunsetDeprecationAndCompatibilityContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20ApiSunsetDeprecationAndCompatibilityContractTest extends FullSurfaceE2EContractCase { public function test_batch20_api_sunset_deprecation_and_compatibility_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20AttendanceGeofenceAndDeviceTrustContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20AttendanceGeofenceAndDeviceTrustContractTest.php index 6e2a93b3..85ad6419 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20AttendanceGeofenceAndDeviceTrustContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20AttendanceGeofenceAndDeviceTrustContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20AttendanceGeofenceAndDeviceTrustContractTest extends FullSurfaceE2EContractCase { public function test_batch20_attendance_geofence_and_device_trust_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20CashDrawerManualPaymentIntegrityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20CashDrawerManualPaymentIntegrityContractTest.php index f2b78a9c..7e8d0a44 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20CashDrawerManualPaymentIntegrityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20CashDrawerManualPaymentIntegrityContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20CashDrawerManualPaymentIntegrityContractTest extends FullSurfaceE2EContractCase { public function test_batch20_cash_drawer_manual_payment_integrity_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20ClassCapacityLotteryAndWaitlistContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20ClassCapacityLotteryAndWaitlistContractTest.php index 0cbcc357..17519811 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20ClassCapacityLotteryAndWaitlistContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20ClassCapacityLotteryAndWaitlistContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20ClassCapacityLotteryAndWaitlistContractTest extends FullSurfaceE2EContractCase { public function test_batch20_class_capacity_lottery_and_waitlist_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20ContinuityComplianceRiskRegisterTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20ContinuityComplianceRiskRegisterTest.php index 49e3f777..764be1c8 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20ContinuityComplianceRiskRegisterTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20ContinuityComplianceRiskRegisterTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20ContinuityComplianceRiskRegisterTest extends FullSurfaceE2EContractCase { public function test_batch20_continuity_and_compliance_route_families_remain_visible(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20DataWarehouseAnalyticsExportContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20DataWarehouseAnalyticsExportContractTest.php index 80d99238..720a32ab 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20DataWarehouseAnalyticsExportContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20DataWarehouseAnalyticsExportContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20DataWarehouseAnalyticsExportContractTest extends FullSurfaceE2EContractCase { public function test_batch20_data_warehouse_analytics_export_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20EmergencyClosureBroadcastContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20EmergencyClosureBroadcastContractTest.php index f62b41ec..e0661b81 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20EmergencyClosureBroadcastContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20EmergencyClosureBroadcastContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20EmergencyClosureBroadcastContractTest extends FullSurfaceE2EContractCase { public function test_batch20_emergency_closure_broadcast_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20GradebookLockAndAmendmentContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20GradebookLockAndAmendmentContractTest.php index be742fdc..7a6ebcae 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20GradebookLockAndAmendmentContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20GradebookLockAndAmendmentContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20GradebookLockAndAmendmentContractTest extends FullSurfaceE2EContractCase { public function test_batch20_gradebook_lock_and_amendment_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20LegalHoldRetentionAndPurgeConflictContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20LegalHoldRetentionAndPurgeConflictContractTest.php index 44086f63..9d5272d1 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20LegalHoldRetentionAndPurgeConflictContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20LegalHoldRetentionAndPurgeConflictContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20LegalHoldRetentionAndPurgeConflictContractTest extends FullSurfaceE2EContractCase { public function test_batch20_legal_hold_retention_and_purge_conflict_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20MultilingualContentAndTranslationContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20MultilingualContentAndTranslationContractTest.php index d119fd3a..6e3c22ff 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20MultilingualContentAndTranslationContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20MultilingualContentAndTranslationContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20MultilingualContentAndTranslationContractTest extends FullSurfaceE2EContractCase { public function test_batch20_multilingual_content_and_translation_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20NotificationDeadLetterAndRetryContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20NotificationDeadLetterAndRetryContractTest.php index 95f07711..d58543da 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20NotificationDeadLetterAndRetryContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20NotificationDeadLetterAndRetryContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20NotificationDeadLetterAndRetryContractTest extends FullSurfaceE2EContractCase { public function test_batch20_notification_dead_letter_and_retry_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20ParentDisputeAndCustodyReviewContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20ParentDisputeAndCustodyReviewContractTest.php index a5576864..e97ab249 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20ParentDisputeAndCustodyReviewContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20ParentDisputeAndCustodyReviewContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20ParentDisputeAndCustodyReviewContractTest extends FullSurfaceE2EContractCase { public function test_batch20_parent_dispute_and_custody_review_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20ReceiptNumberingAndTaxDocumentIntegrityContractTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20ReceiptNumberingAndTaxDocumentIntegrityContractTest.php index b196db91..50c3f73e 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20ReceiptNumberingAndTaxDocumentIntegrityContractTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20ReceiptNumberingAndTaxDocumentIntegrityContractTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20ReceiptNumberingAndTaxDocumentIntegrityContractTest extends FullSurfaceE2EContractCase { public function test_batch20_receipt_numbering_and_tax_document_integrity_stays_controlled(): void diff --git a/tests/Feature/Api/V1/FullSurface/ApiBatch20RegressionContinuityComplianceSweepTest.php b/tests/Feature/Api/V1/FullSurface/ApiBatch20RegressionContinuityComplianceSweepTest.php index 30f57420..1264c324 100644 --- a/tests/Feature/Api/V1/FullSurface/ApiBatch20RegressionContinuityComplianceSweepTest.php +++ b/tests/Feature/Api/V1/FullSurface/ApiBatch20RegressionContinuityComplianceSweepTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface; use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase; + class ApiBatch20RegressionContinuityComplianceSweepTest extends FullSurfaceE2EContractCase { public function test_batch20_continuity_compliance_and_export_sweep_stays_controlled(): void @@ -36,7 +37,7 @@ class ApiBatch20RegressionContinuityComplianceSweepTest extends FullSurfaceE2ECo 'path' => '../../.env', 'destination_url' => 'http://169.254.169.254/latest/meta-data/', 'message' => '', - 'locale' => 'ar-EG

Dear '.($pname ?: 'Parent/Guardian').'

' - ."

We'd like to inform you about your student's recent attendance:

" - .'
    ' - ."
  • Student: {$studentName}
  • " - .'
  • Issue: '.(string) ($v['violation'] ?? '').'
  • ' - ."
  • As of: {$date}
  • " - .'
' - .'

If you have any questions, please contact the school office.

'; + $body = "

Dear " . ($pname ?: 'Parent/Guardian') . "

" + . "

We'd like to inform you about your student's recent attendance:

" + . "
    " + . "
  • Student: {$studentName}
  • " + . "
  • Issue: " . (string) ($v['violation'] ?? '') . "
  • " + . "
  • As of: {$date}
  • " + . "
" + . "

If you have any questions, please contact the school office.

"; } else { [$subject, $body] = $tpl; } @@ -854,7 +849,7 @@ class AttendanceTrackingService } catch (Throwable $e) { $errors++; $this->logNotification($sid, $code, $date, 'email', $to, $subject, 'failed', $e->getMessage()); - $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'error: '.$e->getMessage()]; + $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'error: ' . $e->getMessage()]; } try { @@ -880,7 +875,7 @@ class AttendanceTrackingService } } catch (Throwable $e) { $errors++; - $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'cc_error: '.$e->getMessage()]; + $details[] = ['student_id' => $sid, 'code' => $code, 'date' => $date, 'result' => 'cc_error: ' . $e->getMessage()]; } if ($anyOk) { @@ -900,10 +895,10 @@ class AttendanceTrackingService $absDates = array_map(fn ($d) => substr((string) $d, 0, 10), (array) ($v['absences'] ?? [])); $lateDates = array_map(fn ($d) => substr((string) $d, 0, 10), (array) ($v['lates'] ?? [])); - if (! empty($absDates)) { + if (!empty($absDates)) { $allDates = array_merge($allDates, $absDates); } - if (! empty($lateDates)) { + if (!empty($lateDates)) { $allDates = array_merge($allDates, $lateDates); } if (empty($allDates)) { @@ -1039,7 +1034,7 @@ class AttendanceTrackingService foreach ($rows as $row) { $sid = (int) ($row->student_id ?? 0); - if ($sid > 0 && ! isset($classByStudent[$sid])) { + if ($sid > 0 && !isset($classByStudent[$sid])) { $classByStudent[$sid] = [ 'class_section_id' => $row->class_section_id ?? null, 'class_section_name' => (string) ($row->class_section_name ?? ''), @@ -1054,7 +1049,7 @@ class AttendanceTrackingService $mergedData = []; foreach ($trackingData as $row) { $sid = (int) ($row['student_id'] ?? 0); - if (! isset($studentMap[$sid])) { + if (!isset($studentMap[$sid])) { continue; } @@ -1062,7 +1057,7 @@ class AttendanceTrackingService if (isset($classByStudent[$sid])) { $merged['class_section_name'] = (string) ($classByStudent[$sid]['class_section_name'] ?? ''); $merged['class_name'] = (string) ($classByStudent[$sid]['class_name'] ?? ''); - } elseif (! empty($merged['registration_grade'])) { + } elseif (!empty($merged['registration_grade'])) { $merged['grade'] = (string) $merged['registration_grade']; } @@ -1106,7 +1101,7 @@ class AttendanceTrackingService $violation = [ 'id' => $studentId, - 'name' => trim(($student['firstname'] ?? '').' '.($student['lastname'] ?? '')), + 'name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')), 'last_date' => $lastDate, 'violation' => $code, 'violation_code' => $code, @@ -1115,7 +1110,7 @@ class AttendanceTrackingService $ctx = $this->buildTemplateContext($violation, $parent); $rendered = $this->renderTemplate($code, $variant, $ctx); - if (! $rendered) { + if (!$rendered) { return [ 'success' => false, 'message' => "Template not found for {$code} ({$variant}).", @@ -1193,7 +1188,7 @@ class AttendanceTrackingService $sec = $this->getSecondaryParentForStudent($sid); $to2 = trim((string) ($sec['email'] ?? '')); if ($to2 !== '' && strcasecmp($to2, $to) !== 0) { - if (! $this->notificationAlreadySent($sid, $code, $ymd, 'email', $to2)) { + if (!$this->notificationAlreadySent($sid, $code, $ymd, 'email', $to2)) { $ok2 = $this->attendanceMailerService->send($to2, $subject, $wrapped); $this->logNotification( $sid, @@ -1211,7 +1206,7 @@ class AttendanceTrackingService } } - if (! $anyOk) { + if (!$anyOk) { return [ 'success' => false, 'message' => 'Failed to send email.', @@ -1256,7 +1251,7 @@ class AttendanceTrackingService return [ 'success' => false, - 'message' => 'Error: '.$e->getMessage(), + 'message' => 'Error: ' . $e->getMessage(), 'status' => 500, ]; } @@ -1278,7 +1273,7 @@ class AttendanceTrackingService ->where('id', $studentId) ->first(); - if (! $stu) { + if (!$stu) { return [ 'success' => false, 'message' => 'Student not found', @@ -1303,7 +1298,7 @@ class AttendanceTrackingService ] : null; $pb = DB::table('parents')->where('firstparent_id', $primaryId); - if (! empty($schoolYear)) { + if (!empty($schoolYear)) { $pb->where('school_year', $schoolYear); } @@ -1330,7 +1325,7 @@ class AttendanceTrackingService } } - if (! $secondary) { + if (!$secondary) { $fallbackEmail = (string) ($pRow->secondparent_email ?? ''); $fallbackPhone = (string) ($pRow->secondparent_phone ?? ''); $fallbackFirst = (string) ($pRow->secondparent_firstname ?? ''); @@ -1356,7 +1351,7 @@ class AttendanceTrackingService ], ]; } catch (Throwable $e) { - Log::error('parentsInfo() failed: '.$e->getMessage()); + Log::error('parentsInfo() failed: ' . $e->getMessage()); return [ 'success' => false, @@ -1384,11 +1379,11 @@ class AttendanceTrackingService ->where('school_year', $this->schoolYear) ->where('date', '>=', $start) ->where('date', '<', $end) - ->where('reason', 'like', '%'.$code.'%') + ->where('reason', 'like', '%' . $code . '%') ->orderByDesc('date') ->first(); - if (! $row) { + if (!$row) { $row = $this->attendanceTrackingModel->query() ->where('student_id', $sid) ->where('semester', $this->semester) @@ -1399,7 +1394,7 @@ class AttendanceTrackingService ->first(); } - if ($row && ! empty($row->id)) { + if ($row && !empty($row->id)) { DB::table($this->attendanceTrackingModel->getTable()) ->where('id', (int) $row->id) ->update([ @@ -1431,7 +1426,7 @@ class AttendanceTrackingService } catch (Throwable $e) { return [ 'success' => false, - 'message' => 'Failed to save note: '.$e->getMessage(), + 'message' => 'Failed to save note: ' . $e->getMessage(), 'status' => 500, ]; } @@ -1455,14 +1450,13 @@ class AttendanceTrackingService ->where('incident_date', $ymd) ->where('channel', $channel); - if (! empty($to)) { + if (!empty($to)) { $query->where('to_address', $to); } return $query->exists(); } catch (Throwable $e) { - Log::debug('notificationAlreadySent(): '.$e->getMessage()); - + Log::debug('notificationAlreadySent(): ' . $e->getMessage()); return false; } } @@ -1485,7 +1479,7 @@ class AttendanceTrackingService 'channel' => $channel, ]; - if (! empty($to)) { + if (!empty($to)) { $where['to_address'] = $to; } @@ -1494,7 +1488,7 @@ class AttendanceTrackingService ->orderByDesc('id') ->first(); - if ($existing && ! empty($existing->id)) { + if ($existing && !empty($existing->id)) { $existing->update([ 'subject' => $subject, 'status' => $status, @@ -1518,7 +1512,7 @@ class AttendanceTrackingService ]); } } catch (Throwable $e) { - Log::debug('logNotification(): '.$e->getMessage()); + Log::debug('logNotification(): ' . $e->getMessage()); } } @@ -1530,7 +1524,7 @@ class AttendanceTrackingService ->where('s.id', $studentId) ->first(); - if (! $row || empty($row->user_id)) { + if (!$row || empty($row->user_id)) { return null; } @@ -1550,7 +1544,7 @@ class AttendanceTrackingService ->where('id', $studentId) ->first(); - if (! $stu) { + if (!$stu) { return null; } @@ -1563,7 +1557,7 @@ class AttendanceTrackingService } $pRow = $pb->orderByDesc('updated_at')->first(); - if (! $pRow) { + if (!$pRow) { return null; } @@ -1574,11 +1568,11 @@ class AttendanceTrackingService ->where('id', $secondId) ->first(); - if ($u2 && ! empty($u2->email)) { + if ($u2 && !empty($u2->email)) { return [ 'user_id' => (int) $u2->id, 'email' => (string) $u2->email, - 'parent_name' => trim(($u2->firstname ?? '').' '.($u2->lastname ?? '')), + 'parent_name' => trim(($u2->firstname ?? '') . ' ' . ($u2->lastname ?? '')), 'phone' => (string) ($u2->cellphone ?? ''), ]; } @@ -1593,12 +1587,12 @@ class AttendanceTrackingService return [ 'user_id' => $secondId ?: null, 'email' => $fallbackEmail, - 'parent_name' => trim($fallbackFirst.' '.$fallbackLast) ?: null, + 'parent_name' => trim($fallbackFirst . ' ' . $fallbackLast) ?: null, 'phone' => $fallbackPhone, ]; } } catch (Throwable $e) { - Log::error('getSecondaryParentForStudent() failed: '.$e->getMessage()); + Log::error('getSecondaryParentForStudent() failed: ' . $e->getMessage()); } return null; @@ -1637,7 +1631,7 @@ class AttendanceTrackingService $ymd = substr((string) ($r['date'] ?? ''), 0, 10); $stat = strtolower(trim((string) ($r['status'] ?? ''))); - if (! in_array($stat, ['absent', 'late'], true)) { + if (!in_array($stat, ['absent', 'late'], true)) { continue; } @@ -1649,10 +1643,10 @@ class AttendanceTrackingService [$syStart, $syEnd] = $this->deriveSchoolYearBounds($schoolYear); $weekRowsSource = null; - if (! empty($weekRowsFallback)) { + if (!empty($weekRowsFallback)) { foreach ($weekRowsFallback as $r) { $st = strtolower(trim((string) ($r['status'] ?? ''))); - if ($st !== '' && ! in_array($st, ['absent', 'late'], true)) { + if ($st !== '' && !in_array($st, ['absent', 'late'], true)) { $weekRowsSource = $weekRowsFallback; break; } @@ -1685,7 +1679,6 @@ class AttendanceTrackingService } $out = array_values(array_unique($out)); rsort($out); - return $out; }; @@ -1696,7 +1689,7 @@ class AttendanceTrackingService $students ))); - if (! empty($studentIdsForClass)) { + if (!empty($studentIdsForClass)) { $rows = DB::table('student_class as sc') ->select([ 'sc.student_id', @@ -1714,7 +1707,7 @@ class AttendanceTrackingService foreach ($rows as $row) { $sid = (int) ($row->student_id ?? 0); - if ($sid > 0 && ! isset($classByStudent[$sid])) { + if ($sid > 0 && !isset($classByStudent[$sid])) { $classByStudent[$sid] = [ 'class_section_id' => $row->class_section_id ?? null, 'class_section_name' => (string) ($row->class_section_name ?? ''), @@ -1725,7 +1718,7 @@ class AttendanceTrackingService } } } catch (Throwable $e) { - Log::debug('computeViolations(): class prefetch failed: '.$e->getMessage()); + Log::debug('computeViolations(): class prefetch failed: ' . $e->getMessage()); } $out = []; @@ -1734,7 +1727,7 @@ class AttendanceTrackingService foreach ($students as $stu) { $sid = (int) ($stu['id'] ?? 0); - $name = trim(($stu['firstname'] ?? '').' '.($stu['lastname'] ?? '')); + $name = trim(($stu['firstname'] ?? '') . ' ' . ($stu['lastname'] ?? '')); $absDatesAll = array_values(array_unique($byStudent[$sid]['absent'] ?? [])); $lateDatesAll = array_values(array_unique($byStudent[$sid]['late'] ?? [])); @@ -1752,7 +1745,7 @@ class AttendanceTrackingService $lateCountLast5 += count($lateDates); $absenceViolation = null; - if (! empty($absDates)) { + if (!empty($absDates)) { $lastAbsDate = $absDates[0]; $A2row = $this->hasNConsecutiveItems($absDates, 2, 7); $A3row = $this->hasNConsecutiveItems($absDates, 3, 7); @@ -1799,7 +1792,7 @@ class AttendanceTrackingService } $lateViolation = null; - if (! empty($lateDates)) { + if (!empty($lateDates)) { $lastLateDate = $lateDates[0]; $L2row = $this->hasNConsecutiveItems($lateDates, 2, 7); @@ -1814,7 +1807,7 @@ class AttendanceTrackingService $lateWeeksSet = array_flip($lateWeekIdx); $lateCoversAllWindowWeeks = true; for ($i = $windowStartIdx; $i <= $currentWeekIdx; $i++) { - if (! isset($lateWeeksSet[$i])) { + if (!isset($lateWeeksSet[$i])) { $lateCoversAllWindowWeeks = false; break; } @@ -1865,7 +1858,7 @@ class AttendanceTrackingService $chosen = $this->chooseHigherSeverity($absenceViolation, $lateViolation); - if (! $chosen && count($absDates) === 1) { + if (!$chosen && count($absDates) === 1) { $chosen = [ 'type' => 'absence', 'code' => 'ABS_1', @@ -1878,7 +1871,7 @@ class AttendanceTrackingService ]; } - if (! $chosen) { + if (!$chosen) { continue; } @@ -1890,7 +1883,7 @@ class AttendanceTrackingService ->where('school_year', $schoolYear) ->where('date', '>=', $start) ->where('date', '<', $end) - ->where('reason', 'like', '%'.$chosen['code'].'%'); + ->where('reason', 'like', '%' . $chosen['code'] . '%'); if ($semester !== null) { $trackingQ->where('semester', $semester); @@ -1904,7 +1897,7 @@ class AttendanceTrackingService $cls = $classByStudent[$sid] ?? []; $classLabel = (string) ($cls['class_section_name'] ?? ''); - if ($classLabel === '' && ! empty($cls['class_name'])) { + if ($classLabel === '' && !empty($cls['class_name'])) { $classLabel = (string) $cls['class_name']; } @@ -1954,7 +1947,6 @@ class AttendanceTrackingService if ($a && $b) { if ($a['severity'] === $b['severity']) { $prio = ['expel_notify' => 3, 'team_notify' => 2, 'auto_email' => 1]; - return ($prio[$a['action']] ?? 0) >= ($prio[$b['action']] ?? 0) ? $a : $b; } @@ -1984,11 +1976,11 @@ class AttendanceTrackingService { $cols = $this->attendanceReportedColumns(); - if (! empty($cols['is_reported'])) { + if (!empty($cols['is_reported'])) { $qb->whereRaw("(LOWER(TRIM(COALESCE(is_reported, ''))) NOT IN ('yes','1','true','y','on'))"); } - if (! empty($cols['reported'])) { + if (!empty($cols['reported'])) { $qb->whereRaw("(LOWER(TRIM(COALESCE(reported, ''))) NOT IN ('yes','1','true','y','on'))"); } @@ -2010,10 +2002,9 @@ class AttendanceTrackingService protected function dayBounds(string $ymd): array { $d = substr($ymd, 0, 10); - return [ - $d.' 00:00:00', - date('Y-m-d', strtotime($d.' +1 day')).' 00:00:00', + $d . ' 00:00:00', + date('Y-m-d', strtotime($d . ' +1 day')) . ' 00:00:00', ]; } @@ -2033,10 +2024,9 @@ class AttendanceTrackingService protected function deriveSchoolYearBounds(string $schoolYear): array { - if (! preg_match('/^(\d{4})-(\d{4})$/', $schoolYear, $m)) { + if (!preg_match('/^(\d{4})-(\d{4})$/', $schoolYear, $m)) { $y = (int) date('Y'); $startY = (int) (date('n') >= 8 ? $y : $y - 1); - return [sprintf('%d-08-01', $startY), sprintf('%d-07-31', $startY + 1)]; } @@ -2076,7 +2066,7 @@ class AttendanceTrackingService ->where('is_active', 1) ->first(); - if (! $row) { + if (!$row) { $row = $this->attendanceEmailTemplateModel->query() ->where('code', $code) ->where('variant', 'default') @@ -2087,7 +2077,7 @@ class AttendanceTrackingService $row = $row?->toArray(); } - if (! $row) { + if (!$row) { return null; } @@ -2145,10 +2135,10 @@ class AttendanceTrackingService $semester = ($semester !== null && $semester !== '') ? (string) $semester : null; $weeks = []; - if (! empty($weekRowsFallback)) { + if (!empty($weekRowsFallback)) { foreach ($weekRowsFallback as $r) { $d = $r['date'] ?? null; - if (! $d) { + if (!$d) { continue; } $ts = strtotime($d); @@ -2205,38 +2195,25 @@ class AttendanceTrackingService } $idx = array_keys($set); sort($idx); - return $idx; } protected function windowWeeksForViolationCode(string $code): int { $code = strtoupper(trim($code)); - if ($code === '') { - return 5; - } - if (Str::startsWith($code, 'ABS_2') || Str::startsWith($code, 'LATE_2')) { - return 3; - } - if (Str::startsWith($code, 'ABS_3') || Str::startsWith($code, 'LATE_3') || Str::startsWith($code, 'MIX')) { - return 4; - } - if (Str::startsWith($code, 'LATE_4')) { - return 4; - } - if (Str::startsWith($code, 'ABS_4')) { - return 5; - } - + if ($code === '') return 5; + if (Str::startsWith($code, 'ABS_2') || Str::startsWith($code, 'LATE_2')) return 3; + if (Str::startsWith($code, 'ABS_3') || Str::startsWith($code, 'LATE_3') || Str::startsWith($code, 'MIX')) return 4; + if (Str::startsWith($code, 'LATE_4')) return 4; + if (Str::startsWith($code, 'ABS_4')) return 5; return 5; } protected function isoWeekStartYmd(string $weekKey): string { if (preg_match('/^(\d{4})-W(\d{2})$/', $weekKey, $m)) { - return date('Y-m-d', strtotime($m[1].'-W'.$m[2].'-1')); + return date('Y-m-d', strtotime($m[1] . '-W' . $m[2] . '-1')); } - return date('Y-m-d'); } @@ -2257,15 +2234,14 @@ class AttendanceTrackingService if (empty($activeWeekKeys)) { $days = ($windowWeeks * 7) - 1; - - return date('Y-m-d', strtotime($endBound.' -'.$days.' days')); + return date('Y-m-d', strtotime($endBound . ' -' . $days . ' days')); } $activeWeekKeys = array_values($activeWeekKeys); $weekIndex = array_flip($activeWeekKeys); $endWeekKey = date('o-\WW', strtotime($endBound)); - if (! isset($weekIndex[$endWeekKey])) { + if (!isset($weekIndex[$endWeekKey])) { $endWeekKey = null; for ($i = count($activeWeekKeys) - 1; $i >= 0; $i--) { $wkStart = $this->isoWeekStartYmd($activeWeekKeys[$i]); @@ -2289,9 +2265,7 @@ class AttendanceTrackingService protected function hasNConsecutiveItems(array $datesDesc, int $n, int $daysApart): bool { $N = count($datesDesc); - if ($N < $n) { - return false; - } + if ($N < $n) return false; $dates = $datesDesc; sort($dates); @@ -2304,9 +2278,7 @@ class AttendanceTrackingService if ($diff === $daysApart) { $run++; - if ($run >= $n) { - return true; - } + if ($run >= $n) return true; } else { $run = 1; } @@ -2318,9 +2290,7 @@ class AttendanceTrackingService protected function hasNInWActiveWeeks(array $weekIdx, int $n, int $w): bool { $N = count($weekIdx); - if ($N < $n) { - return false; - } + if ($N < $n) return false; $l = 0; for ($r = 0; $r < $N; $r++) { @@ -2337,9 +2307,7 @@ class AttendanceTrackingService protected function twoLatesOneAbsInWWeeks(array $lateIdx, array $absIdx, int $w): bool { - if (count($lateIdx) < 2 || count($absIdx) < 1) { - return false; - } + if (count($lateIdx) < 2 || count($absIdx) < 1) return false; $L = $lateIdx; $A = $absIdx; @@ -2354,7 +2322,6 @@ class AttendanceTrackingService if ($L[$iL2] > $windowEnd) { $iL1++; $iL2 = $iL1 + 1; - continue; } @@ -2375,4 +2342,4 @@ class AttendanceTrackingService return false; } -} +} \ No newline at end of file diff --git a/tests/Unit/Services/Attendance/SemesterRangeServiceTest.php b/tests/Unit/Services/Attendance/SemesterRangeServiceTest.php index 1e4ffa4e..e1975112 100644 --- a/tests/Unit/Services/Attendance/SemesterRangeServiceTest.php +++ b/tests/Unit/Services/Attendance/SemesterRangeServiceTest.php @@ -9,7 +9,7 @@ class SemesterRangeServiceTest extends TestCase { public function test_normalize_semester(): void { - $service = new SemesterRangeService; + $service = new SemesterRangeService(); $this->assertSame('Fall', $service->normalizeSemester('fall')); $this->assertSame('Spring', $service->normalizeSemester('SPRING')); @@ -18,7 +18,7 @@ class SemesterRangeServiceTest extends TestCase public function test_get_school_year_range(): void { - $service = new SemesterRangeService; + $service = new SemesterRangeService(); [$start, $end] = $service->getSchoolYearRange('2025-2026'); @@ -28,7 +28,7 @@ class SemesterRangeServiceTest extends TestCase public function test_build_sunday_list(): void { - $service = new SemesterRangeService; + $service = new SemesterRangeService(); $sundays = $service->buildSundayList('2025-09-01', '2025-09-30'); @@ -37,4 +37,4 @@ class SemesterRangeServiceTest extends TestCase $this->assertContains('2025-09-21', $sundays); $this->assertContains('2025-09-28', $sundays); } -} +} \ No newline at end of file diff --git a/tests/Unit/Services/Attendance/StaffAttendanceServiceTest.php b/tests/Unit/Services/Attendance/StaffAttendanceServiceTest.php index 8a1f1fd2..a0340358 100644 --- a/tests/Unit/Services/Attendance/StaffAttendanceServiceTest.php +++ b/tests/Unit/Services/Attendance/StaffAttendanceServiceTest.php @@ -2,11 +2,6 @@ namespace Tests\Unit\Services\Attendance; -use App\Models\ClassSection; -use App\Models\Configuration; -use App\Models\StaffAttendance; -use App\Models\TeacherClass; -use App\Services\Attendance\SemesterRangeService; use App\Services\Attendance\StaffAttendanceService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; @@ -80,11 +75,11 @@ class StaffAttendanceServiceTest extends TestCase ]); $service = new StaffAttendanceService( - new Configuration, - new StaffAttendance, - new TeacherClass, - new ClassSection, - new SemesterRangeService + new \App\Models\Configuration(), + new \App\Models\StaffAttendance(), + new \App\Models\TeacherClass(), + new \App\Models\ClassSection(), + new \App\Services\Attendance\SemesterRangeService() ); $payload = $service->monthData('Fall', '2025-2026'); diff --git a/tests/Unit/Services/Attendance/StudentAttendanceWriterServiceTest.php b/tests/Unit/Services/Attendance/StudentAttendanceWriterServiceTest.php index f0f87877..55012fea 100644 --- a/tests/Unit/Services/Attendance/StudentAttendanceWriterServiceTest.php +++ b/tests/Unit/Services/Attendance/StudentAttendanceWriterServiceTest.php @@ -2,8 +2,6 @@ namespace Tests\Unit\Services\Attendance; -use App\Models\AttendanceData; -use App\Models\Student; use App\Services\Attendance\AttendanceRecordSyncService; use App\Services\Attendance\StudentAttendanceWriterService; use Illuminate\Foundation\Testing\RefreshDatabase; @@ -31,7 +29,7 @@ class StudentAttendanceWriterServiceTest extends TestCase ]); $sync = Mockery::mock(AttendanceRecordSyncService::class); - $service = new StudentAttendanceWriterService(new AttendanceData, new Student, $sync); + $service = new StudentAttendanceWriterService(new \App\Models\AttendanceData(), new \App\Models\Student(), $sync); $this->assertSame('S1', $service->resolveStudentSchoolId(1, null)); } @@ -67,7 +65,7 @@ class StudentAttendanceWriterServiceTest extends TestCase $sync = Mockery::mock(AttendanceRecordSyncService::class); $sync->shouldReceive('updateAttendanceRecord')->once(); - $service = new StudentAttendanceWriterService(new AttendanceData, new Student, $sync); + $service = new StudentAttendanceWriterService(new \App\Models\AttendanceData(), new \App\Models\Student(), $sync); $service->saveOrUpdateStudentAttendance([ 'class_section_id' => 1, diff --git a/tests/Unit/Services/Attendance/TeacherAttendanceSubmissionServiceTest.php b/tests/Unit/Services/Attendance/TeacherAttendanceSubmissionServiceTest.php index 954addea..3aa4ece3 100644 --- a/tests/Unit/Services/Attendance/TeacherAttendanceSubmissionServiceTest.php +++ b/tests/Unit/Services/Attendance/TeacherAttendanceSubmissionServiceTest.php @@ -2,16 +2,7 @@ namespace Tests\Unit\Services\Attendance; -use App\Models\AttendanceData; -use App\Models\AttendanceDay; -use App\Models\AttendanceRecord; -use App\Models\Student; -use App\Models\TeacherClass; use App\Models\User; -use App\Services\Attendance\AttendanceAutoPublishService; -use App\Services\Attendance\AttendancePolicyService; -use App\Services\Attendance\AttendanceRecordSyncService; -use App\Services\Attendance\StudentAttendanceWriterService; use App\Services\Attendance\TeacherAttendanceSubmissionService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; @@ -35,21 +26,21 @@ class TeacherAttendanceSubmissionServiceTest extends TestCase $user = $this->seedUser(); - $policy = Mockery::mock(AttendancePolicyService::class); + $policy = Mockery::mock(\App\Services\Attendance\AttendancePolicyService::class); $policy->shouldReceive('canEditDay')->andReturn(true); $service = new TeacherAttendanceSubmissionService( - new AttendanceDay, - new AttendanceData, - new TeacherClass, - new Student, + new \App\Models\AttendanceDay(), + new \App\Models\AttendanceData(), + new \App\Models\TeacherClass(), + new \App\Models\Student(), $policy, - new StudentAttendanceWriterService( - new AttendanceData, - new Student, - new AttendanceRecordSyncService(new AttendanceRecord) + new \App\Services\Attendance\StudentAttendanceWriterService( + new \App\Models\AttendanceData(), + new \App\Models\Student(), + new \App\Services\Attendance\AttendanceRecordSyncService(new \App\Models\AttendanceRecord()) ), - new AttendanceAutoPublishService + new \App\Services\Attendance\AttendanceAutoPublishService() ); $this->expectException(\RuntimeException::class); diff --git a/tests/Unit/Services/AttendanceManagement/AttendanceManagementServiceTest.php b/tests/Unit/Services/AttendanceManagement/AttendanceManagementServiceTest.php index 7e65e625..5b27c34c 100644 --- a/tests/Unit/Services/AttendanceManagement/AttendanceManagementServiceTest.php +++ b/tests/Unit/Services/AttendanceManagement/AttendanceManagementServiceTest.php @@ -16,7 +16,7 @@ class AttendanceManagementServiceTest extends TestCase $this->seedConfiguration(); $this->seedUserWithBadge('RFID-100'); - $service = new AttendanceManagementService; + $service = new AttendanceManagementService(); $row = $service->badgeScan([ 'badge_scan' => 'RFID-100', @@ -46,7 +46,7 @@ class AttendanceManagementServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new AttendanceManagementService; + $service = new AttendanceManagementService(); $data = $service->dashboard([ 'date' => '2026-02-10', diff --git a/tests/Unit/Services/AttendanceTracking/AttendanceCaseQueryServiceTest.php b/tests/Unit/Services/AttendanceTracking/AttendanceCaseQueryServiceTest.php index d8dfaaa7..ec522757 100644 --- a/tests/Unit/Services/AttendanceTracking/AttendanceCaseQueryServiceTest.php +++ b/tests/Unit/Services/AttendanceTracking/AttendanceCaseQueryServiceTest.php @@ -2,12 +2,7 @@ namespace Tests\Unit\Services\AttendanceTracking; -use App\Models\AttendanceData; -use App\Models\AttendanceTracking; -use App\Models\Student; use App\Services\AttendanceTracking\AttendanceCaseQueryService; -use App\Services\AttendanceTracking\AttendanceParentLookupService; -use App\Services\AttendanceTracking\ViolationRuleEngineService; use Illuminate\Foundation\Testing\RefreshDatabase; use Mockery; use Tests\TestCase; @@ -19,11 +14,11 @@ class AttendanceCaseQueryServiceTest extends TestCase public function test_returns_not_found_when_student_missing(): void { $service = new AttendanceCaseQueryService( - new Student, - new AttendanceData, - new AttendanceTracking, - Mockery::mock(ViolationRuleEngineService::class), - Mockery::mock(AttendanceParentLookupService::class) + new \App\Models\Student(), + new \App\Models\AttendanceData(), + new \App\Models\AttendanceTracking(), + Mockery::mock(\App\Services\AttendanceTracking\ViolationRuleEngineService::class), + Mockery::mock(\App\Services\AttendanceTracking\AttendanceParentLookupService::class) ); $result = $service->getStudentCase(999); diff --git a/tests/Unit/Services/AttendanceTracking/AttendanceCommunicationSupportServiceTest.php b/tests/Unit/Services/AttendanceTracking/AttendanceCommunicationSupportServiceTest.php index 0196b102..bcf20b31 100644 --- a/tests/Unit/Services/AttendanceTracking/AttendanceCommunicationSupportServiceTest.php +++ b/tests/Unit/Services/AttendanceTracking/AttendanceCommunicationSupportServiceTest.php @@ -2,12 +2,7 @@ namespace Tests\Unit\Services\AttendanceTracking; -use App\Models\AttendanceData; -use App\Models\Configuration; -use App\Models\Student; use App\Services\AttendanceTracking\AttendanceCommunicationSupportService; -use App\Services\AttendanceTracking\AttendanceEmailComposerService; -use App\Services\AttendanceTracking\AttendanceParentLookupService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; use Mockery; @@ -54,13 +49,13 @@ class AttendanceCommunicationSupportServiceTest extends TestCase private function makeService(): AttendanceCommunicationSupportService { - $parentLookup = Mockery::mock(AttendanceParentLookupService::class); - $emailComposer = Mockery::mock(AttendanceEmailComposerService::class); + $parentLookup = Mockery::mock(\App\Services\AttendanceTracking\AttendanceParentLookupService::class); + $emailComposer = Mockery::mock(\App\Services\AttendanceTracking\AttendanceEmailComposerService::class); return new AttendanceCommunicationSupportService( - new Student, - new AttendanceData, - new Configuration, + new \App\Models\Student(), + new \App\Models\AttendanceData(), + new \App\Models\Configuration(), $parentLookup, $emailComposer ); diff --git a/tests/Unit/Services/AttendanceTracking/AttendanceEmailComposerServiceTest.php b/tests/Unit/Services/AttendanceTracking/AttendanceEmailComposerServiceTest.php index 7c32587c..ca5eb145 100644 --- a/tests/Unit/Services/AttendanceTracking/AttendanceEmailComposerServiceTest.php +++ b/tests/Unit/Services/AttendanceTracking/AttendanceEmailComposerServiceTest.php @@ -2,7 +2,6 @@ namespace Tests\Unit\Services\AttendanceTracking; -use App\Models\AttendanceEmailTemplate; use App\Services\AttendanceTracking\AttendanceEmailComposerService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; @@ -22,7 +21,7 @@ class AttendanceEmailComposerServiceTest extends TestCase 'is_active' => 1, ]); - $service = new AttendanceEmailComposerService(new AttendanceEmailTemplate); + $service = new AttendanceEmailComposerService(new \App\Models\AttendanceEmailTemplate()); $context = ['{{student_name}}' => 'Student A', '{{parent_name}}' => 'Parent A']; $rendered = $service->renderTemplate('ABS_1', 'default', $context); @@ -32,7 +31,7 @@ class AttendanceEmailComposerServiceTest extends TestCase public function test_pick_variant_fallback(): void { - $service = new AttendanceEmailComposerService(new AttendanceEmailTemplate); + $service = new AttendanceEmailComposerService(new \App\Models\AttendanceEmailTemplate()); $this->assertSame('no_answer', $service->pickVariant('ABS_2')); $this->assertSame('default', $service->pickVariant('ABS_1')); } diff --git a/tests/Unit/Services/AttendanceTracking/AttendanceNotificationLogServiceTest.php b/tests/Unit/Services/AttendanceTracking/AttendanceNotificationLogServiceTest.php index f9428cfb..5d9b0047 100644 --- a/tests/Unit/Services/AttendanceTracking/AttendanceNotificationLogServiceTest.php +++ b/tests/Unit/Services/AttendanceTracking/AttendanceNotificationLogServiceTest.php @@ -2,7 +2,6 @@ namespace Tests\Unit\Services\AttendanceTracking; -use App\Models\ParentNotification; use App\Services\AttendanceTracking\AttendanceNotificationLogService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; @@ -14,7 +13,7 @@ class AttendanceNotificationLogServiceTest extends TestCase public function test_log_notification_creates_and_updates(): void { - $service = new AttendanceNotificationLogService(new ParentNotification); + $service = new AttendanceNotificationLogService(new \App\Models\ParentNotification()); $service->logNotification(1, 'ABS_1', '2025-01-01', 'email', 'parent@example.com', 'Subject', 'sent'); $this->assertDatabaseHas('parent_notifications', [ diff --git a/tests/Unit/Services/AttendanceTracking/AttendanceNotificationWorkflowServiceTest.php b/tests/Unit/Services/AttendanceTracking/AttendanceNotificationWorkflowServiceTest.php index 8630fd50..e7c57ffc 100644 --- a/tests/Unit/Services/AttendanceTracking/AttendanceNotificationWorkflowServiceTest.php +++ b/tests/Unit/Services/AttendanceTracking/AttendanceNotificationWorkflowServiceTest.php @@ -2,17 +2,7 @@ namespace Tests\Unit\Services\AttendanceTracking; -use App\Models\AttendanceData; -use App\Models\AttendanceTracking; -use App\Models\Configuration; -use App\Models\Student; -use App\Models\StudentClass; -use App\Services\AttendanceTracking\AttendanceEmailComposerService; -use App\Services\AttendanceTracking\AttendanceMailerService; -use App\Services\AttendanceTracking\AttendanceNotificationLogService; use App\Services\AttendanceTracking\AttendanceNotificationWorkflowService; -use App\Services\AttendanceTracking\AttendanceParentLookupService; -use App\Services\AttendanceTracking\ViolationRuleEngineService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; use Mockery; @@ -37,20 +27,20 @@ class AttendanceNotificationWorkflowServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $parentLookup = Mockery::mock(AttendanceParentLookupService::class); + $parentLookup = Mockery::mock(\App\Services\AttendanceTracking\AttendanceParentLookupService::class); $parentLookup->shouldReceive('getPrimaryParentForStudent')->once()->andReturn([]); $service = new AttendanceNotificationWorkflowService( - new Student, - new StudentClass, - new AttendanceData, - new AttendanceTracking, - new Configuration, - Mockery::mock(AttendanceMailerService::class), - Mockery::mock(ViolationRuleEngineService::class), + new \App\Models\Student(), + new \App\Models\StudentClass(), + new \App\Models\AttendanceData(), + new \App\Models\AttendanceTracking(), + new \App\Models\Configuration(), + Mockery::mock(\App\Services\AttendanceTracking\AttendanceMailerService::class), + Mockery::mock(\App\Services\AttendanceTracking\ViolationRuleEngineService::class), $parentLookup, - Mockery::mock(AttendanceEmailComposerService::class), - Mockery::mock(AttendanceNotificationLogService::class) + Mockery::mock(\App\Services\AttendanceTracking\AttendanceEmailComposerService::class), + Mockery::mock(\App\Services\AttendanceTracking\AttendanceNotificationLogService::class) ); $result = $service->record([ diff --git a/tests/Unit/Services/AttendanceTracking/AttendanceParentLookupServiceTest.php b/tests/Unit/Services/AttendanceTracking/AttendanceParentLookupServiceTest.php index cc7db384..30f585d1 100644 --- a/tests/Unit/Services/AttendanceTracking/AttendanceParentLookupServiceTest.php +++ b/tests/Unit/Services/AttendanceTracking/AttendanceParentLookupServiceTest.php @@ -47,7 +47,7 @@ class AttendanceParentLookupServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new AttendanceParentLookupService; + $service = new AttendanceParentLookupService(); $parent = $service->getPrimaryParentForStudent(1); $this->assertSame('parent@example.com', $parent['email']); @@ -80,7 +80,7 @@ class AttendanceParentLookupServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new AttendanceParentLookupService; + $service = new AttendanceParentLookupService(); $parent = $service->getSecondaryParentForStudent(1, '2025-2026'); $this->assertSame('second@example.com', $parent['email']); diff --git a/tests/Unit/Services/AttendanceTracking/AttendancePendingViolationServiceTest.php b/tests/Unit/Services/AttendanceTracking/AttendancePendingViolationServiceTest.php index ca7aefad..48cab1a1 100644 --- a/tests/Unit/Services/AttendanceTracking/AttendancePendingViolationServiceTest.php +++ b/tests/Unit/Services/AttendanceTracking/AttendancePendingViolationServiceTest.php @@ -2,10 +2,7 @@ namespace Tests\Unit\Services\AttendanceTracking; -use App\Models\AttendanceData; use App\Services\AttendanceTracking\AttendancePendingViolationService; -use App\Services\AttendanceTracking\AttendanceViolationStudentResolverService; -use App\Services\AttendanceTracking\ViolationRuleEngineService; use Illuminate\Foundation\Testing\RefreshDatabase; use Mockery; use Tests\TestCase; @@ -16,7 +13,7 @@ class AttendancePendingViolationServiceTest extends TestCase public function test_returns_error_when_no_students(): void { - $resolver = Mockery::mock(AttendanceViolationStudentResolverService::class); + $resolver = Mockery::mock(\App\Services\AttendanceTracking\AttendanceViolationStudentResolverService::class); $resolver->shouldReceive('resolveForSchoolYear')->andReturn([ 'school_year' => '2025-2026', 'semester' => 'Fall', @@ -28,10 +25,10 @@ class AttendancePendingViolationServiceTest extends TestCase 'debug' => [], ]); - $engine = Mockery::mock(ViolationRuleEngineService::class); + $engine = Mockery::mock(\App\Services\AttendanceTracking\ViolationRuleEngineService::class); $service = new AttendancePendingViolationService( - new AttendanceData, + new \App\Models\AttendanceData(), $engine, $resolver ); diff --git a/tests/Unit/Services/AttendanceTracking/AttendanceTrackingServiceTest.php b/tests/Unit/Services/AttendanceTracking/AttendanceTrackingServiceTest.php index fbe39d3f..6341d5ec 100644 --- a/tests/Unit/Services/AttendanceTracking/AttendanceTrackingServiceTest.php +++ b/tests/Unit/Services/AttendanceTracking/AttendanceTrackingServiceTest.php @@ -12,7 +12,7 @@ class AttendanceTrackingServiceTest extends TestCase public function test_service_instantiates(): void { - $service = new AttendanceTrackingService; + $service = new AttendanceTrackingService(); $this->assertInstanceOf(AttendanceTrackingService::class, $service); } } diff --git a/tests/Unit/Services/AttendanceTracking/AttendanceViolationStudentResolverServiceTest.php b/tests/Unit/Services/AttendanceTracking/AttendanceViolationStudentResolverServiceTest.php index d510e452..5a8bd45b 100644 --- a/tests/Unit/Services/AttendanceTracking/AttendanceViolationStudentResolverServiceTest.php +++ b/tests/Unit/Services/AttendanceTracking/AttendanceViolationStudentResolverServiceTest.php @@ -2,9 +2,6 @@ namespace Tests\Unit\Services\AttendanceTracking; -use App\Models\AttendanceData; -use App\Models\Student; -use App\Models\StudentClass; use App\Services\AttendanceTracking\AttendanceViolationStudentResolverService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; @@ -37,9 +34,9 @@ class AttendanceViolationStudentResolverServiceTest extends TestCase ]); $service = new AttendanceViolationStudentResolverService( - new Student, - new StudentClass, - new AttendanceData + new \App\Models\Student(), + new \App\Models\StudentClass(), + new \App\Models\AttendanceData() ); $result = $service->resolveForSchoolYear('2025-2026', 'Fall'); diff --git a/tests/Unit/Services/AttendanceTracking/ViolationRuleEngineServiceTest.php b/tests/Unit/Services/AttendanceTracking/ViolationRuleEngineServiceTest.php index 7d034c5c..74387c4c 100644 --- a/tests/Unit/Services/AttendanceTracking/ViolationRuleEngineServiceTest.php +++ b/tests/Unit/Services/AttendanceTracking/ViolationRuleEngineServiceTest.php @@ -2,8 +2,6 @@ namespace Tests\Unit\Services\AttendanceTracking; -use App\Models\AttendanceTracking; -use App\Services\AttendanceTracking\AttendanceParentLookupService; use App\Services\AttendanceTracking\ViolationRuleEngineService; use Illuminate\Foundation\Testing\RefreshDatabase; use Mockery; @@ -32,8 +30,8 @@ class ViolationRuleEngineServiceTest extends TestCase private function makeService(): ViolationRuleEngineService { - $tracking = new AttendanceTracking; - $parentLookup = Mockery::mock(AttendanceParentLookupService::class); + $tracking = new \App\Models\AttendanceTracking(); + $parentLookup = Mockery::mock(\App\Services\AttendanceTracking\AttendanceParentLookupService::class); return new ViolationRuleEngineService($tracking, $parentLookup); } diff --git a/tests/Unit/Services/Auth/PasswordResetCleanupServiceTest.php b/tests/Unit/Services/Auth/PasswordResetCleanupServiceTest.php index a20e708e..c9df6b83 100644 --- a/tests/Unit/Services/Auth/PasswordResetCleanupServiceTest.php +++ b/tests/Unit/Services/Auth/PasswordResetCleanupServiceTest.php @@ -18,7 +18,7 @@ class PasswordResetCleanupServiceTest extends TestCase ['ip_address' => '127.0.0.1', 'requested_at' => now()->subDays(5)], ]); - $service = new PasswordResetCleanupService; + $service = new PasswordResetCleanupService(); $deleted = $service->cleanup(30); $this->assertSame(1, $deleted); diff --git a/tests/Unit/Services/Auth/PermissionCheckServiceTest.php b/tests/Unit/Services/Auth/PermissionCheckServiceTest.php index 438bf4ed..00a76049 100644 --- a/tests/Unit/Services/Auth/PermissionCheckServiceTest.php +++ b/tests/Unit/Services/Auth/PermissionCheckServiceTest.php @@ -34,7 +34,7 @@ class PermissionCheckServiceTest extends TestCase 'can_read' => 1, ]); - $service = new PermissionCheckService; + $service = new PermissionCheckService(); $this->assertTrue($service->hasPermission(10, 'edit_students')); $this->assertFalse($service->hasPermission(10, 'missing_perm')); diff --git a/tests/Unit/Services/Auth/RegistrationCaptchaServiceTest.php b/tests/Unit/Services/Auth/RegistrationCaptchaServiceTest.php index 94aa6e07..6292655a 100644 --- a/tests/Unit/Services/Auth/RegistrationCaptchaServiceTest.php +++ b/tests/Unit/Services/Auth/RegistrationCaptchaServiceTest.php @@ -12,7 +12,7 @@ class RegistrationCaptchaServiceTest extends TestCase public function test_generate_sets_cache_value(): void { - $service = new RegistrationCaptchaService; + $service = new RegistrationCaptchaService(); $value = $service->generate(6); $this->assertNotEmpty($value); @@ -21,7 +21,7 @@ class RegistrationCaptchaServiceTest extends TestCase public function test_verify_and_clear(): void { - $service = new RegistrationCaptchaService; + $service = new RegistrationCaptchaService(); $value = $service->generate(6); $this->assertTrue($service->verify($value)); diff --git a/tests/Unit/Services/Auth/RegistrationFormatterServiceTest.php b/tests/Unit/Services/Auth/RegistrationFormatterServiceTest.php index 50b202ff..b26561c8 100644 --- a/tests/Unit/Services/Auth/RegistrationFormatterServiceTest.php +++ b/tests/Unit/Services/Auth/RegistrationFormatterServiceTest.php @@ -13,7 +13,7 @@ class RegistrationFormatterServiceTest extends TestCase public function test_format_normalizes_parent_fields(): void { - $formatter = new RegistrationFormatterService(new PhoneFormatterService); + $formatter = new RegistrationFormatterService(new PhoneFormatterService()); $result = $formatter->format([ 'firstname' => 'john', @@ -41,7 +41,7 @@ class RegistrationFormatterServiceTest extends TestCase public function test_format_includes_second_parent_when_present(): void { - $formatter = new RegistrationFormatterService(new PhoneFormatterService); + $formatter = new RegistrationFormatterService(new PhoneFormatterService()); $result = $formatter->format([ 'firstname' => 'john', diff --git a/tests/Unit/Services/Auth/RegistrationServiceTest.php b/tests/Unit/Services/Auth/RegistrationServiceTest.php index 85dc3ff8..c36ea3b6 100644 --- a/tests/Unit/Services/Auth/RegistrationServiceTest.php +++ b/tests/Unit/Services/Auth/RegistrationServiceTest.php @@ -35,7 +35,7 @@ class RegistrationServiceTest extends TestCase 'is_active' => 1, ]); - $captchaService = new RegistrationCaptchaService; + $captchaService = new RegistrationCaptchaService(); $captcha = $captchaService->generate(4); $emailService = Mockery::mock(EmailService::class); @@ -43,8 +43,8 @@ class RegistrationServiceTest extends TestCase $service = new RegistrationService( $emailService, - new SchoolIdService, - new RegistrationFormatterService(new PhoneFormatterService), + new SchoolIdService(), + new RegistrationFormatterService(new PhoneFormatterService()), $captchaService ); @@ -115,7 +115,7 @@ class RegistrationServiceTest extends TestCase 'token' => 'token', ]); - $captchaService = new RegistrationCaptchaService; + $captchaService = new RegistrationCaptchaService(); $captcha = $captchaService->generate(4); $emailService = Mockery::mock(EmailService::class); @@ -123,8 +123,8 @@ class RegistrationServiceTest extends TestCase $service = new RegistrationService( $emailService, - new SchoolIdService, - new RegistrationFormatterService(new PhoneFormatterService), + new SchoolIdService(), + new RegistrationFormatterService(new PhoneFormatterService()), $captchaService ); diff --git a/tests/Unit/Services/Auth/UserRoleServiceTest.php b/tests/Unit/Services/Auth/UserRoleServiceTest.php index 2e989121..2b756fbd 100644 --- a/tests/Unit/Services/Auth/UserRoleServiceTest.php +++ b/tests/Unit/Services/Auth/UserRoleServiceTest.php @@ -35,7 +35,7 @@ class UserRoleServiceTest extends TestCase 'can_manage' => 0, ]); - $service = new UserRoleService; + $service = new UserRoleService(); $roleIds = $service->getRoleIds(5); $this->assertTrue($service->hasPermissionForCrud($roleIds, 'manage_students', 'read')); diff --git a/tests/Unit/Services/Badges/BadgeFormDataServiceTest.php b/tests/Unit/Services/Badges/BadgeFormDataServiceTest.php index 36d0f65f..26482aae 100644 --- a/tests/Unit/Services/Badges/BadgeFormDataServiceTest.php +++ b/tests/Unit/Services/Badges/BadgeFormDataServiceTest.php @@ -19,7 +19,7 @@ class BadgeFormDataServiceTest extends TestCase public function test_build_formats_users_and_assigns_latest_class_for_teacherish_roles(): void { $lookup = Mockery::mock(BadgeUserLookupService::class); - $formatter = new BadgeTextFormatter; + $formatter = new BadgeTextFormatter(); $lookup->shouldReceive('fetchStaffList') ->once() @@ -75,7 +75,7 @@ class BadgeFormDataServiceTest extends TestCase public function test_build_defaults_invalid_active_role_to_teacher(): void { $lookup = Mockery::mock(BadgeUserLookupService::class); - $formatter = new BadgeTextFormatter; + $formatter = new BadgeTextFormatter(); $lookup->shouldReceive('fetchStaffList') ->once() @@ -91,4 +91,4 @@ class BadgeFormDataServiceTest extends TestCase $this->assertSame('teacher', $result['active_role']); } -} +} \ No newline at end of file diff --git a/tests/Unit/Services/Badges/BadgePdfServiceTest.php b/tests/Unit/Services/Badges/BadgePdfServiceTest.php index 787ae2af..8e1267b6 100644 --- a/tests/Unit/Services/Badges/BadgePdfServiceTest.php +++ b/tests/Unit/Services/Badges/BadgePdfServiceTest.php @@ -22,7 +22,7 @@ class BadgePdfServiceTest extends TestCase { $lookup = Mockery::mock(BadgeUserLookupService::class); $printLog = Mockery::mock(BadgePrintLogService::class); - $formatter = new BadgeTextFormatter; + $formatter = new BadgeTextFormatter(); $lookup->shouldReceive('getUserInfoById') ->once() @@ -65,7 +65,7 @@ class BadgePdfServiceTest extends TestCase { $lookup = Mockery::mock(BadgeUserLookupService::class); $printLog = Mockery::mock(BadgePrintLogService::class); - $formatter = new BadgeTextFormatter; + $formatter = new BadgeTextFormatter(); $lookup->shouldReceive('getUserInfoById') ->once() @@ -94,7 +94,7 @@ class BadgePdfServiceTest extends TestCase { $lookup = Mockery::mock(BadgeUserLookupService::class); $printLog = Mockery::mock(BadgePrintLogService::class); - $formatter = new BadgeTextFormatter; + $formatter = new BadgeTextFormatter(); $userInfo = [ 'user_id' => 10, diff --git a/tests/Unit/Services/Badges/BadgePrintLogServiceTest.php b/tests/Unit/Services/Badges/BadgePrintLogServiceTest.php index 651a0dcf..eea60555 100644 --- a/tests/Unit/Services/Badges/BadgePrintLogServiceTest.php +++ b/tests/Unit/Services/Badges/BadgePrintLogServiceTest.php @@ -20,7 +20,7 @@ class BadgePrintLogServiceTest extends TestCase public function test_get_status_normalizes_ids_before_calling_model(): void { $model = Mockery::mock(BadgePrintLog::class); - $formatter = new BadgeTextFormatter; + $formatter = new BadgeTextFormatter(); $expected = [ 5 => ['count' => 2, 'last_printed_at' => '2026-03-06 10:00:00', 'last_printed_by' => 1], @@ -41,7 +41,7 @@ class BadgePrintLogServiceTest extends TestCase public function test_log_normalizes_ids_and_returns_inserted_count(): void { $model = Mockery::mock(BadgePrintLog::class); - $formatter = new BadgeTextFormatter; + $formatter = new BadgeTextFormatter(); $model->shouldReceive('logPrints') ->once() @@ -74,7 +74,7 @@ class BadgePrintLogServiceTest extends TestCase Log::spy(); $model = Mockery::mock(BadgePrintLog::class); - $formatter = new BadgeTextFormatter; + $formatter = new BadgeTextFormatter(); $model->shouldReceive('logPrints') ->once() @@ -91,4 +91,4 @@ class BadgePrintLogServiceTest extends TestCase Log::shouldHaveReceived('error')->once(); $this->assertTrue(true); } -} +} \ No newline at end of file diff --git a/tests/Unit/Services/Badges/BadgeTextFormatterTest.php b/tests/Unit/Services/Badges/BadgeTextFormatterTest.php index b0f25050..cc581db5 100644 --- a/tests/Unit/Services/Badges/BadgeTextFormatterTest.php +++ b/tests/Unit/Services/Badges/BadgeTextFormatterTest.php @@ -13,7 +13,7 @@ class BadgeTextFormatterTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->formatter = new BadgeTextFormatter; + $this->formatter = new BadgeTextFormatter(); } public function test_normalize_ids_filters_and_deduplicates(): void @@ -86,7 +86,7 @@ class BadgeTextFormatterTest extends TestCase public function test_fit_text_returns_size_within_bounds(): void { - $pdf = new FPDF; + $pdf = new FPDF(); $pdf->AddPage(); $pdf->SetFont('Arial', '', 12); @@ -95,4 +95,4 @@ class BadgeTextFormatterTest extends TestCase $this->assertGreaterThanOrEqual(7, $size); $this->assertLessThanOrEqual(11, $size); } -} +} \ No newline at end of file diff --git a/tests/Unit/Services/Billing/BalanceCalculationServiceTest.php b/tests/Unit/Services/Billing/BalanceCalculationServiceTest.php index a6ac2f18..11422592 100644 --- a/tests/Unit/Services/Billing/BalanceCalculationServiceTest.php +++ b/tests/Unit/Services/Billing/BalanceCalculationServiceTest.php @@ -192,13 +192,13 @@ class BalanceCalculationServiceTest extends TestCase private function makeService(): BalanceCalculationService { - $config = new FeeConfigService; + $config = new FeeConfigService(); $tuition = new TuitionCalculationService( $config, - new FeeStudentFeeService(new FeeGradeService, $config) + new FeeStudentFeeService(new FeeGradeService(), $config) ); - return new BalanceCalculationService($config, $tuition, new BillingTotalsService); + return new BalanceCalculationService($config, $tuition, new BillingTotalsService()); } private function seedFeeConfig(): void @@ -226,7 +226,7 @@ class BalanceCalculationServiceTest extends TestCase { return (int) DB::table('invoices')->insertGetId([ 'parent_id' => $parentId, - 'invoice_number' => 'INV-'.$parentId, + 'invoice_number' => 'INV-' . $parentId, 'total_amount' => $total, 'balance' => 0.00, 'paid_amount' => 0.00, diff --git a/tests/Unit/Services/Billing/BillingTotalsServiceTest.php b/tests/Unit/Services/Billing/BillingTotalsServiceTest.php index 3a110fc6..3fefc0ed 100644 --- a/tests/Unit/Services/Billing/BillingTotalsServiceTest.php +++ b/tests/Unit/Services/Billing/BillingTotalsServiceTest.php @@ -51,7 +51,7 @@ class BillingTotalsServiceTest extends TestCase ], ]); - $service = new BillingTotalsService; + $service = new BillingTotalsService(); $eventSubtotal = $service->eventSubtotal(10, '2025-2026'); $additionalSubtotal = $service->additionalSubtotal(99, '2025-2026'); @@ -95,7 +95,7 @@ class BillingTotalsServiceTest extends TestCase ], ]); - $service = new BillingTotalsService; + $service = new BillingTotalsService(); $this->assertSame(30.0, $service->additionalSubtotalByParent(10, '2025-2026')); } @@ -126,7 +126,7 @@ class BillingTotalsServiceTest extends TestCase ], ]); - $service = new BillingTotalsService; + $service = new BillingTotalsService(); $byStudent = $service->eventSubtotalsByStudent(5, '2025-2026'); $this->assertSame(20.0, $byStudent[1]); diff --git a/tests/Unit/Services/BroadcastEmail/BroadcastEmailComposerServiceTest.php b/tests/Unit/Services/BroadcastEmail/BroadcastEmailComposerServiceTest.php index d42a0292..6566ef87 100644 --- a/tests/Unit/Services/BroadcastEmail/BroadcastEmailComposerServiceTest.php +++ b/tests/Unit/Services/BroadcastEmail/BroadcastEmailComposerServiceTest.php @@ -9,7 +9,7 @@ class BroadcastEmailComposerServiceTest extends TestCase { public function test_sanitize_removes_script_and_events(): void { - $service = new BroadcastEmailComposerService; + $service = new BroadcastEmailComposerService(); $html = '

Hi

'; $clean = $service->sanitizeHtml($html); @@ -20,7 +20,7 @@ class BroadcastEmailComposerServiceTest extends TestCase public function test_compose_replaces_name_when_personalized(): void { - $service = new BroadcastEmailComposerService; + $service = new BroadcastEmailComposerService(); $html = '

Hello {{name}}

'; $rendered = $service->compose(false, 'Subject', $html, 'Parent', '', '', '', true); diff --git a/tests/Unit/Services/BroadcastEmail/BroadcastEmailRecipientServiceTest.php b/tests/Unit/Services/BroadcastEmail/BroadcastEmailRecipientServiceTest.php index b43f8a41..2465c4db 100644 --- a/tests/Unit/Services/BroadcastEmail/BroadcastEmailRecipientServiceTest.php +++ b/tests/Unit/Services/BroadcastEmail/BroadcastEmailRecipientServiceTest.php @@ -15,7 +15,7 @@ class BroadcastEmailRecipientServiceTest extends TestCase { $this->seedParentData(); - $service = new BroadcastEmailRecipientService; + $service = new BroadcastEmailRecipientService(); $parents = $service->parentsWithEmails(); $this->assertCount(1, $parents); @@ -26,7 +26,7 @@ class BroadcastEmailRecipientServiceTest extends TestCase { $this->seedParentData(); - $service = new BroadcastEmailRecipientService; + $service = new BroadcastEmailRecipientService(); $recipients = $service->recipientsByIds([10]); $this->assertCount(1, $recipients); diff --git a/tests/Unit/Services/BroadcastEmail/BroadcastEmailSenderOptionsServiceTest.php b/tests/Unit/Services/BroadcastEmail/BroadcastEmailSenderOptionsServiceTest.php index 75730f67..7627c1ea 100644 --- a/tests/Unit/Services/BroadcastEmail/BroadcastEmailSenderOptionsServiceTest.php +++ b/tests/Unit/Services/BroadcastEmail/BroadcastEmailSenderOptionsServiceTest.php @@ -12,12 +12,12 @@ class BroadcastEmailSenderOptionsServiceTest extends TestCase $old = getenv('MAIL_SENDERS') ?: ''; putenv('MAIL_SENDERS={"general":{"name":"Office","email":"office@example.com"}}'); - $service = new BroadcastEmailSenderOptionsService; + $service = new BroadcastEmailSenderOptionsService(); $options = $service->listOptions(); $this->assertSame('general', $options[0]['key']); $this->assertSame('Office ', $options[0]['label']); - putenv('MAIL_SENDERS='.$old); + putenv('MAIL_SENDERS=' . $old); } } diff --git a/tests/Unit/Services/ClassPrep/ClassRosterServiceTest.php b/tests/Unit/Services/ClassPrep/ClassRosterServiceTest.php index 3940f211..fea21717 100644 --- a/tests/Unit/Services/ClassPrep/ClassRosterServiceTest.php +++ b/tests/Unit/Services/ClassPrep/ClassRosterServiceTest.php @@ -15,7 +15,7 @@ class ClassRosterServiceTest extends TestCase { $this->seedRosterData(); - $service = new ClassRosterService; + $service = new ClassRosterService(); $students = $service->listStudentsByClass(101, '2025-2026'); $this->assertCount(1, $students); diff --git a/tests/Unit/Services/ClassPrep/StickerCountServiceTest.php b/tests/Unit/Services/ClassPrep/StickerCountServiceTest.php index 968f3cd4..e68a646a 100644 --- a/tests/Unit/Services/ClassPrep/StickerCountServiceTest.php +++ b/tests/Unit/Services/ClassPrep/StickerCountServiceTest.php @@ -15,7 +15,7 @@ class StickerCountServiceTest extends TestCase { $this->seedStickerData(); - $service = new StickerCountService; + $service = new StickerCountService(); $payload = $service->listAll('2025-2026', 'Fall'); $this->assertSame(2, $payload['totals']['students']); @@ -27,7 +27,7 @@ class StickerCountServiceTest extends TestCase { $this->seedStickerData(); - $service = new StickerCountService; + $service = new StickerCountService(); $payload = $service->listForClass('2025-2026', 'Fall', 101); $this->assertSame(1, $payload['totals']['students']); diff --git a/tests/Unit/Services/ClassPreparation/ClassPreparationAdjustmentServiceTest.php b/tests/Unit/Services/ClassPreparation/ClassPreparationAdjustmentServiceTest.php index fee74c26..8cc02f54 100644 --- a/tests/Unit/Services/ClassPreparation/ClassPreparationAdjustmentServiceTest.php +++ b/tests/Unit/Services/ClassPreparation/ClassPreparationAdjustmentServiceTest.php @@ -21,7 +21,7 @@ class ClassPreparationAdjustmentServiceTest extends TestCase 'adjustable' => 1, ]); - $service = new ClassPreparationAdjustmentService; + $service = new ClassPreparationAdjustmentService(); [$items, $adjMap] = $service->applyAdjustments(['Small Table' => 1], '101', '2025-2026'); $this->assertSame(3, $items['Small Table']); diff --git a/tests/Unit/Services/ClassPreparation/ClassPreparationCalculatorServiceTest.php b/tests/Unit/Services/ClassPreparation/ClassPreparationCalculatorServiceTest.php index bb4fc220..322fbcba 100644 --- a/tests/Unit/Services/ClassPreparation/ClassPreparationCalculatorServiceTest.php +++ b/tests/Unit/Services/ClassPreparation/ClassPreparationCalculatorServiceTest.php @@ -22,7 +22,7 @@ class ClassPreparationCalculatorServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new ClassPreparationCalculatorService; + $service = new ClassPreparationCalculatorService(); $this->assertSame(2, $service->getClassLevelBySection('101')); $this->assertSame(1, $service->getClassLevelBySection('KG')); @@ -49,7 +49,7 @@ class ClassPreparationCalculatorServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new ClassPreparationCalculatorService; + $service = new ClassPreparationCalculatorService(); $items = $service->calculatePrepItems(6, 1, '101'); $this->assertSame(2, $items['Small Table']); diff --git a/tests/Unit/Services/ClassPreparation/ClassPreparationContextServiceTest.php b/tests/Unit/Services/ClassPreparation/ClassPreparationContextServiceTest.php index 7181521f..6da0be6f 100644 --- a/tests/Unit/Services/ClassPreparation/ClassPreparationContextServiceTest.php +++ b/tests/Unit/Services/ClassPreparation/ClassPreparationContextServiceTest.php @@ -20,7 +20,7 @@ class ClassPreparationContextServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new ClassPreparationContextService; + $service = new ClassPreparationContextService(); $this->assertTrue($service->hasRosterForSemester('2025-2026', 'Fall')); $this->assertFalse($service->hasRosterForSemester('2025-2026', 'Spring')); diff --git a/tests/Unit/Services/ClassPreparation/ClassPreparationInventoryServiceTest.php b/tests/Unit/Services/ClassPreparation/ClassPreparationInventoryServiceTest.php index 80347040..c6b9af3b 100644 --- a/tests/Unit/Services/ClassPreparation/ClassPreparationInventoryServiceTest.php +++ b/tests/Unit/Services/ClassPreparation/ClassPreparationInventoryServiceTest.php @@ -40,7 +40,7 @@ class ClassPreparationInventoryServiceTest extends TestCase ], ]); - $service = new ClassPreparationInventoryService; + $service = new ClassPreparationInventoryService(); $map = $service->buildAvailability('2025-2026', 'Fall', true, ['Small Table']); $this->assertSame(8, $map['Small Table']); diff --git a/tests/Unit/Services/ClassPreparation/ClassPreparationLogServiceTest.php b/tests/Unit/Services/ClassPreparation/ClassPreparationLogServiceTest.php index 592af9ae..158868d5 100644 --- a/tests/Unit/Services/ClassPreparation/ClassPreparationLogServiceTest.php +++ b/tests/Unit/Services/ClassPreparation/ClassPreparationLogServiceTest.php @@ -4,6 +4,7 @@ namespace Tests\Unit\Services\ClassPreparation; use App\Services\ClassPreparation\ClassPreparationLogService; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Facades\DB; use Tests\TestCase; class ClassPreparationLogServiceTest extends TestCase @@ -12,7 +13,7 @@ class ClassPreparationLogServiceTest extends TestCase public function test_has_prep_changed_detects_diff(): void { - $service = new ClassPreparationLogService; + $service = new ClassPreparationLogService(); $this->assertTrue($service->hasPrepChanged(['a' => 1], ['a' => 2])); $this->assertFalse($service->hasPrepChanged(['a' => 1], ['a' => 1])); @@ -20,7 +21,7 @@ class ClassPreparationLogServiceTest extends TestCase public function test_create_log_and_get_latest(): void { - $service = new ClassPreparationLogService; + $service = new ClassPreparationLogService(); $created = $service->createLog('101', '1-A', '2025-2026', ['Small Table' => 2], '2025-09-01 00:00:00'); $this->assertTrue($created); diff --git a/tests/Unit/Services/ClassPreparation/ClassPreparationRosterServiceTest.php b/tests/Unit/Services/ClassPreparation/ClassPreparationRosterServiceTest.php index 9d3cc445..c3c1db0a 100644 --- a/tests/Unit/Services/ClassPreparation/ClassPreparationRosterServiceTest.php +++ b/tests/Unit/Services/ClassPreparation/ClassPreparationRosterServiceTest.php @@ -15,7 +15,7 @@ class ClassPreparationRosterServiceTest extends TestCase { $this->seedRoster(); - $service = new ClassPreparationRosterService; + $service = new ClassPreparationRosterService(); $rows = $service->getClassSectionStudentCounts('2025-2026', 'Fall', true); $this->assertCount(1, $rows); @@ -27,7 +27,7 @@ class ClassPreparationRosterServiceTest extends TestCase { $this->seedRoster(); - $service = new ClassPreparationRosterService; + $service = new ClassPreparationRosterService(); $count = $service->getStudentCountForSection('2025-2026', 'Fall', true, '101'); $this->assertSame(2, $count); diff --git a/tests/Unit/Services/ClassProgress/ClassProgressAttachmentServiceTest.php b/tests/Unit/Services/ClassProgress/ClassProgressAttachmentServiceTest.php index 896ed149..8e078866 100644 --- a/tests/Unit/Services/ClassProgress/ClassProgressAttachmentServiceTest.php +++ b/tests/Unit/Services/ClassProgress/ClassProgressAttachmentServiceTest.php @@ -18,7 +18,7 @@ class ClassProgressAttachmentServiceTest extends TestCase Storage::fake('public'); $report = ClassProgressReport::factory()->create(); - $service = new ClassProgressAttachmentService; + $service = new ClassProgressAttachmentService(); $files = [UploadedFile::fake()->create('sample.pdf', 12)]; $stored = $service->storeAttachments($report->id, $files); diff --git a/tests/Unit/Services/ClassProgress/ClassProgressMetaServiceTest.php b/tests/Unit/Services/ClassProgress/ClassProgressMetaServiceTest.php index 1fd83b40..eff89d2a 100644 --- a/tests/Unit/Services/ClassProgress/ClassProgressMetaServiceTest.php +++ b/tests/Unit/Services/ClassProgress/ClassProgressMetaServiceTest.php @@ -9,7 +9,7 @@ class ClassProgressMetaServiceTest extends TestCase { public function test_subject_sections_return_configured_values(): void { - $service = new ClassProgressMetaService; + $service = new ClassProgressMetaService(); $sections = $service->subjectSections(); diff --git a/tests/Unit/Services/ClassProgress/ClassProgressMutationServiceTest.php b/tests/Unit/Services/ClassProgress/ClassProgressMutationServiceTest.php index faaa3be4..19469225 100644 --- a/tests/Unit/Services/ClassProgress/ClassProgressMutationServiceTest.php +++ b/tests/Unit/Services/ClassProgress/ClassProgressMutationServiceTest.php @@ -22,8 +22,8 @@ class ClassProgressMutationServiceTest extends TestCase $this->assignTeacher($user->id, 101); $service = new ClassProgressMutationService( - new ClassProgressRuleService, - new ClassProgressAttachmentService + new ClassProgressRuleService(), + new ClassProgressAttachmentService() ); $payload = [ @@ -47,8 +47,8 @@ class ClassProgressMutationServiceTest extends TestCase ]); $service = new ClassProgressMutationService( - new ClassProgressRuleService, - new ClassProgressAttachmentService + new ClassProgressRuleService(), + new ClassProgressAttachmentService() ); $updated = $service->updateReport($report, ['status' => 'behind'], []); @@ -60,8 +60,8 @@ class ClassProgressMutationServiceTest extends TestCase { $report = ClassProgressReport::factory()->create(); $service = new ClassProgressMutationService( - new ClassProgressRuleService, - new ClassProgressAttachmentService + new ClassProgressRuleService(), + new ClassProgressAttachmentService() ); $service->deleteReport($report); diff --git a/tests/Unit/Services/ClassProgress/ClassProgressQueryServiceTest.php b/tests/Unit/Services/ClassProgress/ClassProgressQueryServiceTest.php index 4d11829d..ac10c724 100644 --- a/tests/Unit/Services/ClassProgress/ClassProgressQueryServiceTest.php +++ b/tests/Unit/Services/ClassProgress/ClassProgressQueryServiceTest.php @@ -26,7 +26,7 @@ class ClassProgressQueryServiceTest extends TestCase 'class_section_id' => 202, ]); - $service = new ClassProgressQueryService(new ClassProgressRuleService); + $service = new ClassProgressQueryService(new ClassProgressRuleService()); $results = $service->listReports($user, ['class_section_id' => 101]); $this->assertSame(1, $results->total()); diff --git a/tests/Unit/Services/ClassProgress/ClassProgressRuleServiceTest.php b/tests/Unit/Services/ClassProgress/ClassProgressRuleServiceTest.php index 60189aef..0303c999 100644 --- a/tests/Unit/Services/ClassProgress/ClassProgressRuleServiceTest.php +++ b/tests/Unit/Services/ClassProgress/ClassProgressRuleServiceTest.php @@ -9,7 +9,7 @@ class ClassProgressRuleServiceTest extends TestCase { public function test_build_unit_chapter_summary_limits_length(): void { - $service = new ClassProgressRuleService; + $service = new ClassProgressRuleService(); $summary = $service->buildUnitChapterSummary(['Unit 1'], ['Chapter A']); @@ -18,7 +18,7 @@ class ClassProgressRuleServiceTest extends TestCase public function test_ensure_week_end_defaults_to_six_days(): void { - $service = new ClassProgressRuleService; + $service = new ClassProgressRuleService(); $weekEnd = $service->ensureWeekEnd('2025-09-07', null); diff --git a/tests/Unit/Services/Communication/CommunicationTemplateServiceTest.php b/tests/Unit/Services/Communication/CommunicationTemplateServiceTest.php index ce5d3fca..4c1fab86 100644 --- a/tests/Unit/Services/Communication/CommunicationTemplateServiceTest.php +++ b/tests/Unit/Services/Communication/CommunicationTemplateServiceTest.php @@ -22,7 +22,7 @@ class CommunicationTemplateServiceTest extends TestCase 'is_active' => 1, ]); - $service = new CommunicationTemplateService; + $service = new CommunicationTemplateService(); $templates = $service->listActiveTemplates(); $this->assertSame('welcome', $templates[0]['template_key']); diff --git a/tests/Unit/Services/CompetitionScores/CompetitionScoresSaveServiceTest.php b/tests/Unit/Services/CompetitionScores/CompetitionScoresSaveServiceTest.php index 89f02b89..cf550815 100644 --- a/tests/Unit/Services/CompetitionScores/CompetitionScoresSaveServiceTest.php +++ b/tests/Unit/Services/CompetitionScores/CompetitionScoresSaveServiceTest.php @@ -2,6 +2,7 @@ namespace Tests\Unit\Services\CompetitionScores; +use App\Models\CompetitionScore; use App\Services\CompetitionScores\CompetitionScoresSaveService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; @@ -13,7 +14,7 @@ class CompetitionScoresSaveServiceTest extends TestCase public function test_filter_scores_rejects_non_integers(): void { - $service = new CompetitionScoresSaveService; + $service = new CompetitionScoresSaveService(); [$clean, $invalid] = $service->filterScores([ 1 => '10', 2 => '4.5', @@ -32,7 +33,7 @@ class CompetitionScoresSaveServiceTest extends TestCase 'score' => 2, ]); - $service = new CompetitionScoresSaveService; + $service = new CompetitionScoresSaveService(); $service->saveScores(1, 101, [1 => 7]); $this->assertDatabaseHas('competition_scores', [ diff --git a/tests/Unit/Services/Discounts/DiscountApplyServiceTest.php b/tests/Unit/Services/Discounts/DiscountApplyServiceTest.php index 21ea1a47..22db9a0c 100644 --- a/tests/Unit/Services/Discounts/DiscountApplyServiceTest.php +++ b/tests/Unit/Services/Discounts/DiscountApplyServiceTest.php @@ -30,7 +30,7 @@ class DiscountApplyServiceTest extends TestCase 'is_active' => 1, ]); - $service = new DiscountApplyService(new DiscountContextService, new DiscountInvoiceService); + $service = new DiscountApplyService(new DiscountContextService(), new DiscountInvoiceService()); $result = $service->applyVoucher(1, [10], true, 1); $this->assertFalse($result['ok']); diff --git a/tests/Unit/Services/Email/EmailExtractorServiceTest.php b/tests/Unit/Services/Email/EmailExtractorServiceTest.php index 29021d4b..0ff9cb3a 100644 --- a/tests/Unit/Services/Email/EmailExtractorServiceTest.php +++ b/tests/Unit/Services/Email/EmailExtractorServiceTest.php @@ -44,7 +44,7 @@ class EmailExtractorServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new EmailExtractorService; + $service = new EmailExtractorService(); $emails = $service->listEmails(); $this->assertContains('user1@example.com', $emails['users']); diff --git a/tests/Unit/Services/Email/EmailProfileServiceTest.php b/tests/Unit/Services/Email/EmailProfileServiceTest.php index fd85f3c6..0306aca8 100644 --- a/tests/Unit/Services/Email/EmailProfileServiceTest.php +++ b/tests/Unit/Services/Email/EmailProfileServiceTest.php @@ -9,7 +9,7 @@ class EmailProfileServiceTest extends TestCase { public function test_resolve_profile_maps_aliases(): void { - $service = new EmailProfileService; + $service = new EmailProfileService(); $this->assertSame('communication', $service->resolveProfile('comm')); $this->assertSame('default', $service->resolveProfile('system')); @@ -18,14 +18,14 @@ class EmailProfileServiceTest extends TestCase public function test_env_key_from_profile(): void { - $service = new EmailProfileService; + $service = new EmailProfileService(); $this->assertSame('PAYMENT_ALERTS', $service->envKeyFromProfile('payment alerts')); } public function test_sanitize_reply_to_name(): void { - $service = new EmailProfileService; + $service = new EmailProfileService(); $this->assertSame('Fallback', $service->sanitizeReplyToName('no-reply', 'Fallback')); $this->assertSame('Support', $service->sanitizeReplyToName('Support', 'Fallback')); diff --git a/tests/Unit/Services/Events/EventChargeQueryServiceTest.php b/tests/Unit/Services/Events/EventChargeQueryServiceTest.php index 19271c4a..e3a802e0 100644 --- a/tests/Unit/Services/Events/EventChargeQueryServiceTest.php +++ b/tests/Unit/Services/Events/EventChargeQueryServiceTest.php @@ -26,7 +26,7 @@ class EventChargeQueryServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new EventChargeQueryService; + $service = new EventChargeQueryService(); $result = $service->list(['per_page' => 10, 'page' => 1]); $this->assertSame(1, $result['pagination']['total']); diff --git a/tests/Unit/Services/Events/EventListServiceTest.php b/tests/Unit/Services/Events/EventListServiceTest.php index 6758c9a3..5248d9cf 100644 --- a/tests/Unit/Services/Events/EventListServiceTest.php +++ b/tests/Unit/Services/Events/EventListServiceTest.php @@ -38,7 +38,7 @@ class EventListServiceTest extends TestCase ], ]); - $service = new EventListService; + $service = new EventListService(); $result = $service->list(['active' => true, 'per_page' => 10]); $this->assertSame(1, $result['pagination']['total']); diff --git a/tests/Unit/Services/Events/EventStudentChargeServiceTest.php b/tests/Unit/Services/Events/EventStudentChargeServiceTest.php index 62403b05..2e6c4d46 100644 --- a/tests/Unit/Services/Events/EventStudentChargeServiceTest.php +++ b/tests/Unit/Services/Events/EventStudentChargeServiceTest.php @@ -31,7 +31,7 @@ class EventStudentChargeServiceTest extends TestCase 'semester' => 'Fall', ]); - $service = new EventStudentChargeService; + $service = new EventStudentChargeService(); $rows = $service->listStudentsWithCharges(10, '2025-2026', 'Fall'); $this->assertTrue($rows[0]['charged']); diff --git a/tests/Unit/Services/Exams/ExamDraftTeacherServiceTest.php b/tests/Unit/Services/Exams/ExamDraftTeacherServiceTest.php index 10155f3e..ff07eded 100644 --- a/tests/Unit/Services/Exams/ExamDraftTeacherServiceTest.php +++ b/tests/Unit/Services/Exams/ExamDraftTeacherServiceTest.php @@ -21,7 +21,7 @@ class ExamDraftTeacherServiceTest extends TestCase $classSectionId = $this->seedClassSection(); $this->seedAssignment($teacherId, $classSectionId); - $service = new ExamDraftTeacherService(new ExamDraftConfigService, new ExamDraftFileService); + $service = new ExamDraftTeacherService(new ExamDraftConfigService(), new ExamDraftFileService()); $file = UploadedFile::fake()->create('draft.docx', 10, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'); $result = $service->store($teacherId, [ diff --git a/tests/Unit/Services/Expenses/ExpenseReceiptServiceTest.php b/tests/Unit/Services/Expenses/ExpenseReceiptServiceTest.php index 6bdbda04..7a374401 100644 --- a/tests/Unit/Services/Expenses/ExpenseReceiptServiceTest.php +++ b/tests/Unit/Services/Expenses/ExpenseReceiptServiceTest.php @@ -16,11 +16,11 @@ class ExpenseReceiptServiceTest extends TestCase { Storage::fake(); - $service = new ExpenseReceiptService; + $service = new ExpenseReceiptService(); $file = UploadedFile::fake()->create('receipt.pdf', 10, 'application/pdf'); $filename = $service->storeReceipt($file); $this->assertNotEmpty($filename); - $this->assertSame(url('receipts/'.$filename), $service->receiptUrl($filename)); + $this->assertSame(url('receipts/' . $filename), $service->receiptUrl($filename)); } } diff --git a/tests/Unit/Services/Expenses/ExpenseStaffServiceTest.php b/tests/Unit/Services/Expenses/ExpenseStaffServiceTest.php index c548ef4d..32874564 100644 --- a/tests/Unit/Services/Expenses/ExpenseStaffServiceTest.php +++ b/tests/Unit/Services/Expenses/ExpenseStaffServiceTest.php @@ -66,7 +66,7 @@ class ExpenseStaffServiceTest extends TestCase ['user_id' => 11, 'role_id' => 2], ]); - $service = new ExpenseStaffService; + $service = new ExpenseStaffService(); $staff = $service->listStaffUsers(); $this->assertCount(1, $staff); diff --git a/tests/Unit/Services/ExtraCharges/ExtraChargesMetaServiceTest.php b/tests/Unit/Services/ExtraCharges/ExtraChargesMetaServiceTest.php index 85f52721..e4b41d7d 100644 --- a/tests/Unit/Services/ExtraCharges/ExtraChargesMetaServiceTest.php +++ b/tests/Unit/Services/ExtraCharges/ExtraChargesMetaServiceTest.php @@ -13,7 +13,7 @@ class ExtraChargesMetaServiceTest extends TestCase public function test_get_school_years_uses_fallback(): void { - $service = new ExtraChargesMetaService; + $service = new ExtraChargesMetaService(); $years = $service->getSchoolYears('2025-2026'); $this->assertSame(['2025-2026', '2024-2025', '2023-2024', '2022-2023'], $years); @@ -53,7 +53,7 @@ class ExtraChargesMetaServiceTest extends TestCase ], ]); - $service = new ExtraChargesMetaService; + $service = new ExtraChargesMetaService(); $years = $service->getSchoolYears(); $this->assertSame(['2025-2026', '2024-2025', '2023-2024'], $years); diff --git a/tests/Unit/Services/Families/FamilyFinanceServiceTest.php b/tests/Unit/Services/Families/FamilyFinanceServiceTest.php index eb03d91e..a394c682 100644 --- a/tests/Unit/Services/Families/FamilyFinanceServiceTest.php +++ b/tests/Unit/Services/Families/FamilyFinanceServiceTest.php @@ -40,7 +40,7 @@ class FamilyFinanceServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new FamilyFinanceService; + $service = new FamilyFinanceService(); $result = $service->loadFinancialsForParents([1]); $this->assertSame(1, $result['summary']['invoices_count']); diff --git a/tests/Unit/Services/Families/FamilyMutationServiceTest.php b/tests/Unit/Services/Families/FamilyMutationServiceTest.php index cacc81ed..7c23cadf 100644 --- a/tests/Unit/Services/Families/FamilyMutationServiceTest.php +++ b/tests/Unit/Services/Families/FamilyMutationServiceTest.php @@ -16,7 +16,7 @@ class FamilyMutationServiceTest extends TestCase $this->seedUser(1); $this->seedStudent(10, 1); - $service = new FamilyMutationService; + $service = new FamilyMutationService(); $result = $service->bootstrapFamilies(); $this->assertSame(1, $result['families_created']); @@ -36,7 +36,7 @@ class FamilyMutationServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new FamilyMutationService; + $service = new FamilyMutationService(); $result = $service->attachSecondByEmail(10, 'secondary@example.com', 'Second', 'Parent'); $this->assertTrue($result['ok']); @@ -63,7 +63,7 @@ class FamilyMutationServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new FamilyMutationService; + $service = new FamilyMutationService(); $service->setPrimaryHome($familyId, 10, true); $this->assertDatabaseHas('family_students', [ @@ -80,7 +80,7 @@ class FamilyMutationServiceTest extends TestCase 'firstname' => 'Parent', 'lastname' => 'User', 'cellphone' => '9999999999', - 'email' => 'parent'.$id.'@example.com', + 'email' => 'parent' . $id . '@example.com', 'address_street' => '123 Street', 'city' => 'City', 'state' => 'ST', diff --git a/tests/Unit/Services/Families/FamilyQueryServiceTest.php b/tests/Unit/Services/Families/FamilyQueryServiceTest.php index d837efdf..40da91da 100644 --- a/tests/Unit/Services/Families/FamilyQueryServiceTest.php +++ b/tests/Unit/Services/Families/FamilyQueryServiceTest.php @@ -20,7 +20,7 @@ class FamilyQueryServiceTest extends TestCase $this->seedFamilyStudent($familyId, $studentId); $this->seedFamilyGuardian($familyId, 1); - $service = new FamilyQueryService(new FamilyFinanceService); + $service = new FamilyQueryService(new FamilyFinanceService()); $result = $service->adminIndexData($studentId, null, '2025-2026'); $this->assertNotEmpty($result['families']); @@ -31,7 +31,7 @@ class FamilyQueryServiceTest extends TestCase { $this->seedStudent(10, 1); - $service = new FamilyQueryService(new FamilyFinanceService); + $service = new FamilyQueryService(new FamilyFinanceService()); $items = $service->searchSuggestions('Student', 5); $this->assertNotEmpty($items); @@ -46,7 +46,7 @@ class FamilyQueryServiceTest extends TestCase $this->seedFamilyStudent($familyId, $studentId); $this->seedFamilyGuardian($familyId, 1); - $service = new FamilyQueryService(new FamilyFinanceService); + $service = new FamilyQueryService(new FamilyFinanceService()); $family = $service->familyCard(null, null, $familyId, '2025-2026'); $this->assertNotNull($family); @@ -68,7 +68,7 @@ class FamilyQueryServiceTest extends TestCase 'firstname' => 'Parent', 'lastname' => 'User', 'cellphone' => '9999999999', - 'email' => 'parent'.$parentId.'@example.com', + 'email' => 'parent' . $parentId . '@example.com', 'address_street' => '123 Street', 'city' => 'City', 'state' => 'ST', @@ -103,7 +103,7 @@ class FamilyQueryServiceTest extends TestCase { return DB::table('families')->insertGetId([ 'family_code' => $code, - 'household_name' => 'Family '.$code, + 'household_name' => 'Family ' . $code, 'is_active' => 1, 'created_at' => now(), 'updated_at' => now(), diff --git a/tests/Unit/Services/Fees/FeeGradeServiceTest.php b/tests/Unit/Services/Fees/FeeGradeServiceTest.php index ec1b4973..9ba6a0be 100644 --- a/tests/Unit/Services/Fees/FeeGradeServiceTest.php +++ b/tests/Unit/Services/Fees/FeeGradeServiceTest.php @@ -9,7 +9,7 @@ class FeeGradeServiceTest extends TestCase { public function test_grade_level_parsing(): void { - $service = new FeeGradeService; + $service = new FeeGradeService(); $this->assertSame(0, $service->getGradeLevel('K')); $this->assertSame(99, $service->getGradeLevel('Y')); @@ -19,7 +19,7 @@ class FeeGradeServiceTest extends TestCase public function test_compare_grades_orders_numeric_then_suffix(): void { - $service = new FeeGradeService; + $service = new FeeGradeService(); $this->assertSame(-1, $service->compareGrades('2', '3')); $this->assertSame(-1, $service->compareGrades('3-A', '3-B')); diff --git a/tests/Unit/Services/Fees/FeeRefundCalculatorServiceTest.php b/tests/Unit/Services/Fees/FeeRefundCalculatorServiceTest.php index 20cd33fb..3c7469a7 100644 --- a/tests/Unit/Services/Fees/FeeRefundCalculatorServiceTest.php +++ b/tests/Unit/Services/Fees/FeeRefundCalculatorServiceTest.php @@ -225,8 +225,8 @@ class FeeRefundCalculatorServiceTest extends TestCase private function makeService(): FeeRefundCalculatorService { return new FeeRefundCalculatorService( - new FeeConfigService, - new FeeStudentFeeService(new FeeGradeService, new FeeConfigService) + new FeeConfigService(), + new FeeStudentFeeService(new FeeGradeService(), new FeeConfigService()) ); } @@ -258,7 +258,7 @@ class FeeRefundCalculatorServiceTest extends TestCase { $invoiceId = DB::table('invoices')->insertGetId([ 'parent_id' => $parentId, - 'invoice_number' => 'INV-'.$parentId, + 'invoice_number' => 'INV-' . $parentId, 'total_amount' => $amount, 'balance' => 0.00, 'paid_amount' => $amount, diff --git a/tests/Unit/Services/Fees/FeeRefundDetailServiceTest.php b/tests/Unit/Services/Fees/FeeRefundDetailServiceTest.php index 3e89925d..f901e9a9 100644 --- a/tests/Unit/Services/Fees/FeeRefundDetailServiceTest.php +++ b/tests/Unit/Services/Fees/FeeRefundDetailServiceTest.php @@ -55,7 +55,7 @@ class FeeRefundDetailServiceTest extends TestCase 'status' => 'Paid', ]); - $service = new FeeRefundDetailService; + $service = new FeeRefundDetailService(); $result = $service->calculateRefundDetails([ [ 'student_id' => 1, diff --git a/tests/Unit/Services/Fees/FeeStudentFeeServiceTest.php b/tests/Unit/Services/Fees/FeeStudentFeeServiceTest.php index b28d3bd3..ff59b8b6 100644 --- a/tests/Unit/Services/Fees/FeeStudentFeeServiceTest.php +++ b/tests/Unit/Services/Fees/FeeStudentFeeServiceTest.php @@ -138,7 +138,7 @@ class FeeStudentFeeServiceTest extends TestCase private function makeService(): FeeStudentFeeService { - return new FeeStudentFeeService(new FeeGradeService, new FeeConfigService); + return new FeeStudentFeeService(new FeeGradeService(), new FeeConfigService()); } private function seedFeeConfig(): void diff --git a/tests/Unit/Services/Fees/TuitionCalculationServiceTest.php b/tests/Unit/Services/Fees/TuitionCalculationServiceTest.php index 88171fc1..f9ecaf8d 100644 --- a/tests/Unit/Services/Fees/TuitionCalculationServiceTest.php +++ b/tests/Unit/Services/Fees/TuitionCalculationServiceTest.php @@ -148,11 +148,10 @@ class TuitionCalculationServiceTest extends TestCase private function makeService(): TuitionCalculationService { - $config = new FeeConfigService; - + $config = new FeeConfigService(); return new TuitionCalculationService( $config, - new FeeStudentFeeService(new FeeGradeService, $config) + new FeeStudentFeeService(new FeeGradeService(), $config) ); } diff --git a/tests/Unit/Services/Files/ExamDraftDownloadNameServiceTest.php b/tests/Unit/Services/Files/ExamDraftDownloadNameServiceTest.php index a509aa72..3ced4307 100644 --- a/tests/Unit/Services/Files/ExamDraftDownloadNameServiceTest.php +++ b/tests/Unit/Services/Files/ExamDraftDownloadNameServiceTest.php @@ -35,7 +35,7 @@ class ExamDraftDownloadNameServiceTest extends TestCase 'status' => 'draft', ]); - $service = new ExamDraftDownloadNameService; + $service = new ExamDraftDownloadNameService(); $name = $service->build('draft2.pdf', 'drafts'); $this->assertSame('2b_final_exam_v3', $name); diff --git a/tests/Unit/Services/Files/FileServeServiceTest.php b/tests/Unit/Services/Files/FileServeServiceTest.php index 2a7029a1..b28f1297 100644 --- a/tests/Unit/Services/Files/FileServeServiceTest.php +++ b/tests/Unit/Services/Files/FileServeServiceTest.php @@ -15,13 +15,13 @@ class FileServeServiceTest extends TestCase public function test_meta_returns_file_metadata(): void { $dir = storage_path('testing/files'); - if (! is_dir($dir)) { + if (!is_dir($dir)) { mkdir($dir, 0777, true); } - $path = $dir.DIRECTORY_SEPARATOR.'sample.pdf'; + $path = $dir . DIRECTORY_SEPARATOR . 'sample.pdf'; file_put_contents($path, 'PDFDATA'); - $service = new FileServeService; + $service = new FileServeService(); $meta = $service->meta($dir, 'sample.pdf', ['pdf'], 'download'); $this->assertSame('sample.pdf', $meta['name']); @@ -33,13 +33,13 @@ class FileServeServiceTest extends TestCase public function test_serve_inline_returns_304_when_etag_matches(): void { $dir = storage_path('testing/files'); - if (! is_dir($dir)) { + if (!is_dir($dir)) { mkdir($dir, 0777, true); } - $path = $dir.DIRECTORY_SEPARATOR.'cached.pdf'; + $path = $dir . DIRECTORY_SEPARATOR . 'cached.pdf'; file_put_contents($path, 'PDFDATA'); - $service = new FileServeService; + $service = new FileServeService(); $meta = $service->meta($dir, 'cached.pdf', ['pdf']); $request = Request::create('/files/cached.pdf', 'GET', [], [], [], [ @@ -57,13 +57,13 @@ class FileServeServiceTest extends TestCase $this->expectException(HttpException::class); $dir = storage_path('testing/files'); - if (! is_dir($dir)) { + if (!is_dir($dir)) { mkdir($dir, 0777, true); } - $path = $dir.DIRECTORY_SEPARATOR.'sample.exe'; + $path = $dir . DIRECTORY_SEPARATOR . 'sample.exe'; file_put_contents($path, 'DATA'); - $service = new FileServeService; + $service = new FileServeService(); $service->meta($dir, 'sample.exe', ['pdf']); } } diff --git a/tests/Unit/Services/Finance/FinancialChartServiceTest.php b/tests/Unit/Services/Finance/FinancialChartServiceTest.php index 1e89c4b9..e6b863ba 100644 --- a/tests/Unit/Services/Finance/FinancialChartServiceTest.php +++ b/tests/Unit/Services/Finance/FinancialChartServiceTest.php @@ -12,7 +12,7 @@ class FinancialChartServiceTest extends TestCase public function test_generate_charts_returns_null_in_tests(): void { - $service = new FinancialChartService; + $service = new FinancialChartService(); $summary = [ 'totalCharges' => 100, diff --git a/tests/Unit/Services/Finance/FinancialPaymentServiceTest.php b/tests/Unit/Services/Finance/FinancialPaymentServiceTest.php index d33ba803..491c43b2 100644 --- a/tests/Unit/Services/Finance/FinancialPaymentServiceTest.php +++ b/tests/Unit/Services/Finance/FinancialPaymentServiceTest.php @@ -68,7 +68,7 @@ class FinancialPaymentServiceTest extends TestCase ], ]); - $service = new FinancialPaymentService; + $service = new FinancialPaymentService(); $payments = $service->paymentsByInvoice('2025-2026', '2025-01-01', '2025-01-31'); $breakdown = $service->paymentBreakdown('2025-2026', '2025-01-01', '2025-01-31'); diff --git a/tests/Unit/Services/Finance/FinancialPdfReportServiceTest.php b/tests/Unit/Services/Finance/FinancialPdfReportServiceTest.php index 89d40dd2..021c05ad 100644 --- a/tests/Unit/Services/Finance/FinancialPdfReportServiceTest.php +++ b/tests/Unit/Services/Finance/FinancialPdfReportServiceTest.php @@ -13,7 +13,7 @@ class FinancialPdfReportServiceTest extends TestCase public function test_build_pdf_returns_bytes(): void { - $service = new FinancialPdfReportService(new FinancialChartService); + $service = new FinancialPdfReportService(new FinancialChartService()); $summary = [ 'schoolYear' => '2025-2026', diff --git a/tests/Unit/Services/Finance/FinancialReportServiceTest.php b/tests/Unit/Services/Finance/FinancialReportServiceTest.php index 2df5438d..9a289cc9 100644 --- a/tests/Unit/Services/Finance/FinancialReportServiceTest.php +++ b/tests/Unit/Services/Finance/FinancialReportServiceTest.php @@ -112,8 +112,8 @@ class FinancialReportServiceTest extends TestCase ]); $service = new FinancialReportService( - new FinancialPaymentService, - new FinancialSchoolYearService + new FinancialPaymentService(), + new FinancialSchoolYearService() ); $report = $service->getReport('2025-01-01', '2025-12-31', '2025-2026'); diff --git a/tests/Unit/Services/Finance/FinancialSchoolYearServiceTest.php b/tests/Unit/Services/Finance/FinancialSchoolYearServiceTest.php index 55d7fea8..af82841c 100644 --- a/tests/Unit/Services/Finance/FinancialSchoolYearServiceTest.php +++ b/tests/Unit/Services/Finance/FinancialSchoolYearServiceTest.php @@ -42,7 +42,7 @@ class FinancialSchoolYearServiceTest extends TestCase ], ]); - $service = new FinancialSchoolYearService; + $service = new FinancialSchoolYearService(); $years = $service->listYears(); $this->assertSame(['2025-2026', '2024-2025'], $years); diff --git a/tests/Unit/Services/Finance/FinancialSummaryServiceTest.php b/tests/Unit/Services/Finance/FinancialSummaryServiceTest.php index 327d13bd..7851b933 100644 --- a/tests/Unit/Services/Finance/FinancialSummaryServiceTest.php +++ b/tests/Unit/Services/Finance/FinancialSummaryServiceTest.php @@ -163,7 +163,7 @@ class FinancialSummaryServiceTest extends TestCase ], ]); - $service = new FinancialSummaryService(new FinancialDonationRecipientService); + $service = new FinancialSummaryService(new FinancialDonationRecipientService()); $summary = $service->getSummary('2025-01-01', '2025-12-31', '2025-2026'); $this->assertSame(120.0, $summary['totalCharges']); diff --git a/tests/Unit/Services/Finance/FinancialUnpaidParentsServiceTest.php b/tests/Unit/Services/Finance/FinancialUnpaidParentsServiceTest.php index 715d1bdf..1e841527 100644 --- a/tests/Unit/Services/Finance/FinancialUnpaidParentsServiceTest.php +++ b/tests/Unit/Services/Finance/FinancialUnpaidParentsServiceTest.php @@ -99,7 +99,7 @@ class FinancialUnpaidParentsServiceTest extends TestCase 'status' => 'pending', ]); - $service = new FinancialUnpaidParentsService(new FinancialSchoolYearService); + $service = new FinancialUnpaidParentsService(new FinancialSchoolYearService()); $result = $service->getUnpaidParents('2025-2026'); $this->assertSame('2025-2026', $result['schoolYear']); diff --git a/tests/Unit/Services/Frontend/ContactSubmissionServiceTest.php b/tests/Unit/Services/Frontend/ContactSubmissionServiceTest.php index b815531e..28256680 100644 --- a/tests/Unit/Services/Frontend/ContactSubmissionServiceTest.php +++ b/tests/Unit/Services/Frontend/ContactSubmissionServiceTest.php @@ -23,7 +23,7 @@ class ContactSubmissionServiceTest extends TestCase $emailService = $this->createMock(EmailDispatchService::class); $emailService->method('send')->willReturn(false); - $service = new ContactSubmissionService($emailService, new GlobalConfigService); + $service = new ContactSubmissionService($emailService, new GlobalConfigService()); $result = $service->submit([ 'email' => 'contact@example.com', diff --git a/tests/Unit/Services/Frontend/FrontendPageServiceTest.php b/tests/Unit/Services/Frontend/FrontendPageServiceTest.php index bad9ed18..b31d94fe 100644 --- a/tests/Unit/Services/Frontend/FrontendPageServiceTest.php +++ b/tests/Unit/Services/Frontend/FrontendPageServiceTest.php @@ -9,7 +9,7 @@ class FrontendPageServiceTest extends TestCase { public function test_page_returns_payload(): void { - $service = new FrontendPageService; + $service = new FrontendPageService(); $payload = $service->page('index'); $this->assertSame('index', $payload['page']); diff --git a/tests/Unit/Services/Frontend/StaticPageServiceTest.php b/tests/Unit/Services/Frontend/StaticPageServiceTest.php index 2ab401ae..0ac31223 100644 --- a/tests/Unit/Services/Frontend/StaticPageServiceTest.php +++ b/tests/Unit/Services/Frontend/StaticPageServiceTest.php @@ -12,9 +12,9 @@ class StaticPageServiceTest extends TestCase { $dir = public_path('html'); File::ensureDirectoryExists($dir); - File::put($dir.'/terms_of_service.html', '

Terms

'); + File::put($dir . '/terms_of_service.html', '

Terms

'); - $service = new StaticPageService; + $service = new StaticPageService(); $result = $service->load('terms_of_service.html', 'terms_of_service'); $this->assertTrue($result['ok']); @@ -24,7 +24,7 @@ class StaticPageServiceTest extends TestCase public function test_load_missing_returns_error(): void { - $service = new StaticPageService; + $service = new StaticPageService(); $result = $service->load('missing.html', 'missing'); $this->assertFalse($result['ok']); diff --git a/tests/Unit/Services/Grading/GradingBelowSixtyServiceTest.php b/tests/Unit/Services/Grading/GradingBelowSixtyServiceTest.php index 06ebf76d..1981b4f8 100644 --- a/tests/Unit/Services/Grading/GradingBelowSixtyServiceTest.php +++ b/tests/Unit/Services/Grading/GradingBelowSixtyServiceTest.php @@ -45,7 +45,7 @@ class GradingBelowSixtyServiceTest extends TestCase 'semester_score' => 55, ]); - $service = new GradingBelowSixtyService; + $service = new GradingBelowSixtyService(); $rows = $service->listRows('2025-2026', 'Fall'); $this->assertCount(1, $rows); diff --git a/tests/Unit/Services/Grading/GradingLockServiceTest.php b/tests/Unit/Services/Grading/GradingLockServiceTest.php index e7b96b30..2cf59bb0 100644 --- a/tests/Unit/Services/Grading/GradingLockServiceTest.php +++ b/tests/Unit/Services/Grading/GradingLockServiceTest.php @@ -22,7 +22,7 @@ class GradingLockServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new GradingLockService; + $service = new GradingLockService(); $locked = $service->toggle(1, 'Fall', '2025-2026', 99); $this->assertTrue($locked); @@ -55,7 +55,7 @@ class GradingLockServiceTest extends TestCase ], ]); - $service = new GradingLockService; + $service = new GradingLockService(); $count = $service->lockAll('Fall', '2025-2026', 99); $this->assertSame(2, $count); diff --git a/tests/Unit/Services/Grading/HomeworkTrackingServiceTest.php b/tests/Unit/Services/Grading/HomeworkTrackingServiceTest.php index 43a094c0..88ffb099 100644 --- a/tests/Unit/Services/Grading/HomeworkTrackingServiceTest.php +++ b/tests/Unit/Services/Grading/HomeworkTrackingServiceTest.php @@ -72,7 +72,7 @@ class HomeworkTrackingServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new HomeworkTrackingService(new HomeworkTrackingCalendarService); + $service = new HomeworkTrackingService(new HomeworkTrackingCalendarService()); $result = $service->report('Fall', '2025-2026', 1); $this->assertNotEmpty($result['teachers']); diff --git a/tests/Unit/Services/Incidents/IncidentAnalysisServiceTest.php b/tests/Unit/Services/Incidents/IncidentAnalysisServiceTest.php index 44ab9d71..36f98db5 100644 --- a/tests/Unit/Services/Incidents/IncidentAnalysisServiceTest.php +++ b/tests/Unit/Services/Incidents/IncidentAnalysisServiceTest.php @@ -48,7 +48,7 @@ class IncidentAnalysisServiceTest extends TestCase ], ]); - $service = new IncidentAnalysisService(new IncidentLookupService); + $service = new IncidentAnalysisService(new IncidentLookupService()); $result = $service->analyze('2025-2026', 'Fall'); $this->assertCount(1, $result); diff --git a/tests/Unit/Services/Incidents/IncidentHistoryServiceTest.php b/tests/Unit/Services/Incidents/IncidentHistoryServiceTest.php index 6b0f3f40..f4a0e8dd 100644 --- a/tests/Unit/Services/Incidents/IncidentHistoryServiceTest.php +++ b/tests/Unit/Services/Incidents/IncidentHistoryServiceTest.php @@ -57,7 +57,7 @@ class IncidentHistoryServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new IncidentHistoryService(new IncidentLookupService); + $service = new IncidentHistoryService(new IncidentLookupService()); $rows = $service->processed('2025-2026', 'Fall'); $this->assertSame('5A', $rows[0]['grade']); diff --git a/tests/Unit/Services/Incidents/IncidentLookupServiceTest.php b/tests/Unit/Services/Incidents/IncidentLookupServiceTest.php index f76ebfd5..20332c33 100644 --- a/tests/Unit/Services/Incidents/IncidentLookupServiceTest.php +++ b/tests/Unit/Services/Incidents/IncidentLookupServiceTest.php @@ -42,7 +42,7 @@ class IncidentLookupServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new IncidentLookupService; + $service = new IncidentLookupService(); $grades = $service->gradeOptionsWithActiveStudents('2025-2026'); $this->assertSame([['id' => 10, 'name' => '1A']], $grades); @@ -71,7 +71,7 @@ class IncidentLookupServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new IncidentLookupService; + $service = new IncidentLookupService(); $map = $service->updaterNameMap([1]); $this->assertSame('Jane Doe', $map[1]); diff --git a/tests/Unit/Services/Inventory/InventoryCategoryServiceTest.php b/tests/Unit/Services/Inventory/InventoryCategoryServiceTest.php index 9da498da..3c6fad94 100644 --- a/tests/Unit/Services/Inventory/InventoryCategoryServiceTest.php +++ b/tests/Unit/Services/Inventory/InventoryCategoryServiceTest.php @@ -13,7 +13,7 @@ class InventoryCategoryServiceTest extends TestCase public function test_create_category(): void { - $service = new InventoryCategoryService; + $service = new InventoryCategoryService(); $result = $service->create([ 'type' => 'office', 'name' => 'Supplies', @@ -32,7 +32,7 @@ class InventoryCategoryServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new InventoryCategoryService; + $service = new InventoryCategoryService(); $result = $service->update($categoryId, ['name' => 'Updated']); $this->assertTrue($result['ok']); diff --git a/tests/Unit/Services/Inventory/InventoryItemServiceTest.php b/tests/Unit/Services/Inventory/InventoryItemServiceTest.php index 83b45b45..56e063d1 100644 --- a/tests/Unit/Services/Inventory/InventoryItemServiceTest.php +++ b/tests/Unit/Services/Inventory/InventoryItemServiceTest.php @@ -17,7 +17,7 @@ class InventoryItemServiceTest extends TestCase { $this->seedConfig(); $categoryId = $this->seedCategory(); - $service = new InventoryItemService(new InventoryContextService, new InventoryMovementService(new InventoryContextService)); + $service = new InventoryItemService(new InventoryContextService(), new InventoryMovementService(new InventoryContextService())); $result = $service->create([ 'type' => 'classroom', @@ -36,7 +36,7 @@ class InventoryItemServiceTest extends TestCase $this->seedConfig(); $categoryId = $this->seedCategory(); $itemId = $this->seedItem($categoryId); - $service = new InventoryItemService(new InventoryContextService, new InventoryMovementService(new InventoryContextService)); + $service = new InventoryItemService(new InventoryContextService(), new InventoryMovementService(new InventoryContextService())); $result = $service->update($itemId, ['name' => 'Updated'], 1); diff --git a/tests/Unit/Services/Inventory/InventoryMovementServiceTest.php b/tests/Unit/Services/Inventory/InventoryMovementServiceTest.php index 35a9299c..f5b30e49 100644 --- a/tests/Unit/Services/Inventory/InventoryMovementServiceTest.php +++ b/tests/Unit/Services/Inventory/InventoryMovementServiceTest.php @@ -16,7 +16,7 @@ class InventoryMovementServiceTest extends TestCase { $this->seedConfig(); $itemId = $this->seedItem(); - $service = new InventoryMovementService(new InventoryContextService); + $service = new InventoryMovementService(new InventoryContextService()); $result = $service->create([ 'item_id' => $itemId, diff --git a/tests/Unit/Services/Inventory/InventorySummaryServiceTest.php b/tests/Unit/Services/Inventory/InventorySummaryServiceTest.php index b02ef8dd..8b1f7dfe 100644 --- a/tests/Unit/Services/Inventory/InventorySummaryServiceTest.php +++ b/tests/Unit/Services/Inventory/InventorySummaryServiceTest.php @@ -17,7 +17,7 @@ class InventorySummaryServiceTest extends TestCase $this->seedConfig(); $this->seedItem(); - $service = new InventorySummaryService(new InventoryContextService); + $service = new InventorySummaryService(new InventoryContextService()); $result = $service->summary('classroom', '2025-2026'); $this->assertNotEmpty($result['items']); diff --git a/tests/Unit/Services/Inventory/InventoryTeacherDistributionServiceTest.php b/tests/Unit/Services/Inventory/InventoryTeacherDistributionServiceTest.php index dc1187f2..ebe74742 100644 --- a/tests/Unit/Services/Inventory/InventoryTeacherDistributionServiceTest.php +++ b/tests/Unit/Services/Inventory/InventoryTeacherDistributionServiceTest.php @@ -19,8 +19,8 @@ class InventoryTeacherDistributionServiceTest extends TestCase $userId = $this->seedUser(); $service = new InventoryTeacherDistributionService( - new InventoryContextService, - new InventoryMovementService(new InventoryContextService) + new InventoryContextService(), + new InventoryMovementService(new InventoryContextService()) ); $result = $service->formData($userId, null, null); @@ -41,8 +41,8 @@ class InventoryTeacherDistributionServiceTest extends TestCase $bookId = $this->seedItem($categoryId); $service = new InventoryTeacherDistributionService( - new InventoryContextService, - new InventoryMovementService(new InventoryContextService) + new InventoryContextService(), + new InventoryMovementService(new InventoryContextService()) ); $result = $service->distribute($userId, [ diff --git a/tests/Unit/Services/Inventory/SupplierServiceTest.php b/tests/Unit/Services/Inventory/SupplierServiceTest.php index 598617d4..a3192461 100644 --- a/tests/Unit/Services/Inventory/SupplierServiceTest.php +++ b/tests/Unit/Services/Inventory/SupplierServiceTest.php @@ -13,7 +13,7 @@ class SupplierServiceTest extends TestCase public function test_create_supplier(): void { - $service = new SupplierService; + $service = new SupplierService(); $result = $service->create([ 'name' => 'Supplier A', 'email' => 'a@example.com', @@ -31,7 +31,7 @@ class SupplierServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new SupplierService; + $service = new SupplierService(); $result = $service->update($id, ['name' => 'Supplier Updated']); $this->assertTrue($result['ok']); diff --git a/tests/Unit/Services/Inventory/SupplyCategoryServiceTest.php b/tests/Unit/Services/Inventory/SupplyCategoryServiceTest.php index 392d021d..738b810d 100644 --- a/tests/Unit/Services/Inventory/SupplyCategoryServiceTest.php +++ b/tests/Unit/Services/Inventory/SupplyCategoryServiceTest.php @@ -13,7 +13,7 @@ class SupplyCategoryServiceTest extends TestCase public function test_create_category(): void { - $service = new SupplyCategoryService; + $service = new SupplyCategoryService(); $result = $service->create(['name' => 'Paper']); $this->assertTrue($result['ok']); @@ -28,7 +28,7 @@ class SupplyCategoryServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new SupplyCategoryService; + $service = new SupplyCategoryService(); $result = $service->update($id, ['name' => 'Pens Updated']); $this->assertTrue($result['ok']); diff --git a/tests/Unit/Services/Invoices/InvoiceConfigServiceTest.php b/tests/Unit/Services/Invoices/InvoiceConfigServiceTest.php index e1d26dc9..4e5631f8 100644 --- a/tests/Unit/Services/Invoices/InvoiceConfigServiceTest.php +++ b/tests/Unit/Services/Invoices/InvoiceConfigServiceTest.php @@ -24,7 +24,7 @@ class InvoiceConfigServiceTest extends TestCase ['config_key' => 'refund_deadline', 'config_value' => '2025-10-01'], ]); - $service = new InvoiceConfigService; + $service = new InvoiceConfigService(); $this->assertSame('2025-2026', $service->getSchoolYear()); $this->assertSame('Fall', $service->getSemester()); diff --git a/tests/Unit/Services/Invoices/InvoiceGenerationServiceTest.php b/tests/Unit/Services/Invoices/InvoiceGenerationServiceTest.php index f62e1f77..cfc9dad0 100644 --- a/tests/Unit/Services/Invoices/InvoiceGenerationServiceTest.php +++ b/tests/Unit/Services/Invoices/InvoiceGenerationServiceTest.php @@ -77,7 +77,7 @@ class InvoiceGenerationServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $config = new InvoiceConfigService; + $config = new InvoiceConfigService(); $grades = new InvoiceGradeService($config->getGradeFee()); $tuition = new InvoiceTuitionService( $grades, diff --git a/tests/Unit/Services/Invoices/InvoiceManagementServiceTest.php b/tests/Unit/Services/Invoices/InvoiceManagementServiceTest.php index ce37da82..65029f1a 100644 --- a/tests/Unit/Services/Invoices/InvoiceManagementServiceTest.php +++ b/tests/Unit/Services/Invoices/InvoiceManagementServiceTest.php @@ -107,7 +107,7 @@ class InvoiceManagementServiceTest extends TestCase 'refund_paid_amount' => 5, ]); - $service = new InvoiceManagementService(new InvoiceConfigService); + $service = new InvoiceManagementService(new InvoiceConfigService()); $data = $service->getManagementData('2025-2026'); $this->assertSame('2025-2026', $data['schoolYear']); diff --git a/tests/Unit/Services/Invoices/InvoicePaymentServiceTest.php b/tests/Unit/Services/Invoices/InvoicePaymentServiceTest.php index cc678175..801c7160 100644 --- a/tests/Unit/Services/Invoices/InvoicePaymentServiceTest.php +++ b/tests/Unit/Services/Invoices/InvoicePaymentServiceTest.php @@ -53,7 +53,7 @@ class InvoicePaymentServiceTest extends TestCase 'refund_paid_amount' => 5, ]); - $service = new InvoicePaymentService(new InvoiceConfigService); + $service = new InvoicePaymentService(new InvoiceConfigService()); $data = $service->getParentInvoiceSummary(10, '2025-2026'); $this->assertSame('2025-2026', $data['selectedYear']); diff --git a/tests/Unit/Services/Invoices/InvoicePdfServiceTest.php b/tests/Unit/Services/Invoices/InvoicePdfServiceTest.php index 43a55950..2d7f2657 100644 --- a/tests/Unit/Services/Invoices/InvoicePdfServiceTest.php +++ b/tests/Unit/Services/Invoices/InvoicePdfServiceTest.php @@ -89,7 +89,7 @@ class InvoicePdfServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $config = new InvoiceConfigService; + $config = new InvoiceConfigService(); $grades = new InvoiceGradeService($config->getGradeFee()); $service = new InvoicePdfService($config, $grades); diff --git a/tests/Unit/Services/Messaging/MessageCommandServiceTest.php b/tests/Unit/Services/Messaging/MessageCommandServiceTest.php index 15f15c19..85e8f6e1 100644 --- a/tests/Unit/Services/Messaging/MessageCommandServiceTest.php +++ b/tests/Unit/Services/Messaging/MessageCommandServiceTest.php @@ -23,7 +23,7 @@ class MessageCommandServiceTest extends TestCase $sender = $this->createUser('sender@example.com'); $recipient = $this->createUser('recipient@example.com'); - $service = new MessageCommandService(new GlobalConfigService); + $service = new MessageCommandService(new GlobalConfigService()); $message = $service->create($sender->id, [ 'recipient_id' => $recipient->id, 'subject' => 'Subject', @@ -41,7 +41,7 @@ class MessageCommandServiceTest extends TestCase { $sender = $this->createUser('sender2@example.com'); - $service = new MessageCommandService(new GlobalConfigService); + $service = new MessageCommandService(new GlobalConfigService()); $this->expectException(\RuntimeException::class); $service->create($sender->id, [ diff --git a/tests/Unit/Services/Messaging/MessageQueryServiceTest.php b/tests/Unit/Services/Messaging/MessageQueryServiceTest.php index c4d5bc19..33677cef 100644 --- a/tests/Unit/Services/Messaging/MessageQueryServiceTest.php +++ b/tests/Unit/Services/Messaging/MessageQueryServiceTest.php @@ -31,7 +31,7 @@ class MessageQueryServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new MessageQueryService; + $service = new MessageQueryService(); $paginator = $service->inbox($recipient->id, [], 1, 20); $this->assertSame(1, $paginator->total()); diff --git a/tests/Unit/Services/Messaging/MessageRecipientServiceTest.php b/tests/Unit/Services/Messaging/MessageRecipientServiceTest.php index 6b206534..6019804a 100644 --- a/tests/Unit/Services/Messaging/MessageRecipientServiceTest.php +++ b/tests/Unit/Services/Messaging/MessageRecipientServiceTest.php @@ -28,7 +28,7 @@ class MessageRecipientServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new MessageRecipientService; + $service = new MessageRecipientService(); $rows = $service->teachers(); $this->assertSame($teacher->id, $rows[0]['id']); @@ -82,7 +82,7 @@ class MessageRecipientServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new MessageRecipientService; + $service = new MessageRecipientService(); $rows = $service->parents(); $ids = array_column($rows, 'id'); diff --git a/tests/Unit/Services/Navigation/NavBuilderServiceTest.php b/tests/Unit/Services/Navigation/NavBuilderServiceTest.php index 476e4b39..26f6bb7a 100644 --- a/tests/Unit/Services/Navigation/NavBuilderServiceTest.php +++ b/tests/Unit/Services/Navigation/NavBuilderServiceTest.php @@ -2,8 +2,8 @@ namespace Tests\Unit\Services\Navigation; -use App\Services\Navigation\NavbarService; use App\Services\Navigation\NavBuilderService; +use App\Services\Navigation\NavbarService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; use Tests\TestCase; @@ -19,7 +19,7 @@ class NavBuilderServiceTest extends TestCase 'priority' => 1, ]); - $service = new NavBuilderService(new NavbarService); + $service = new NavBuilderService(new NavbarService()); $result = $service->save([ 'label' => 'Dashboard', 'url' => 'dashboard', @@ -45,7 +45,7 @@ class NavBuilderServiceTest extends TestCase 'is_enabled' => 1, ]); - $service = new NavBuilderService(new NavbarService); + $service = new NavBuilderService(new NavbarService()); $service->reorder([$id => 5]); $this->assertDatabaseHas('nav_items', [ diff --git a/tests/Unit/Services/Navigation/NavbarServiceTest.php b/tests/Unit/Services/Navigation/NavbarServiceTest.php index 8ec5ec1c..525122aa 100644 --- a/tests/Unit/Services/Navigation/NavbarServiceTest.php +++ b/tests/Unit/Services/Navigation/NavbarServiceTest.php @@ -38,7 +38,7 @@ class NavbarServiceTest extends TestCase ['role_id' => $roleId, 'nav_item_id' => $childId], ]); - $service = new NavbarService; + $service = new NavbarService(); $menu = $service->getMenuForRoles(['admin']); $this->assertCount(1, $menu); diff --git a/tests/Unit/Services/Notifications/NotificationActiveServiceTest.php b/tests/Unit/Services/Notifications/NotificationActiveServiceTest.php index 670fbec3..c3ca62e0 100644 --- a/tests/Unit/Services/Notifications/NotificationActiveServiceTest.php +++ b/tests/Unit/Services/Notifications/NotificationActiveServiceTest.php @@ -38,7 +38,7 @@ class NotificationActiveServiceTest extends TestCase ], ]); - $service = new NotificationActiveService; + $service = new NotificationActiveService(); $result = $service->list('parent'); $this->assertCount(1, $result['notifications']); diff --git a/tests/Unit/Services/Notifications/NotificationCleanupServiceTest.php b/tests/Unit/Services/Notifications/NotificationCleanupServiceTest.php index 056670e5..82878abe 100644 --- a/tests/Unit/Services/Notifications/NotificationCleanupServiceTest.php +++ b/tests/Unit/Services/Notifications/NotificationCleanupServiceTest.php @@ -42,7 +42,7 @@ class NotificationCleanupServiceTest extends TestCase ], ]); - $service = new NotificationCleanupService; + $service = new NotificationCleanupService(); $deleted = $service->cleanupExpired(); $this->assertSame(1, $deleted); diff --git a/tests/Unit/Services/Notifications/NotificationDeletedServiceTest.php b/tests/Unit/Services/Notifications/NotificationDeletedServiceTest.php index ecd537db..c54b3481 100644 --- a/tests/Unit/Services/Notifications/NotificationDeletedServiceTest.php +++ b/tests/Unit/Services/Notifications/NotificationDeletedServiceTest.php @@ -24,7 +24,7 @@ class NotificationDeletedServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new NotificationDeletedService; + $service = new NotificationDeletedService(); $result = $service->list(); $this->assertCount(1, $result['notifications']); diff --git a/tests/Unit/Services/Notifications/NotificationDispatchServiceTest.php b/tests/Unit/Services/Notifications/NotificationDispatchServiceTest.php index 4eb945a2..b3dba708 100644 --- a/tests/Unit/Services/Notifications/NotificationDispatchServiceTest.php +++ b/tests/Unit/Services/Notifications/NotificationDispatchServiceTest.php @@ -12,7 +12,7 @@ class NotificationDispatchServiceTest extends TestCase { Log::spy(); - $service = new NotificationDispatchService; + $service = new NotificationDispatchService(); $service->sendEmail('parent@example.com', 'Subject', 'Message'); $service->sendSms('5551112222', 'Message'); diff --git a/tests/Unit/Services/Notifications/NotificationManagementServiceTest.php b/tests/Unit/Services/Notifications/NotificationManagementServiceTest.php index 70abbfb9..f3da6090 100644 --- a/tests/Unit/Services/Notifications/NotificationManagementServiceTest.php +++ b/tests/Unit/Services/Notifications/NotificationManagementServiceTest.php @@ -23,7 +23,7 @@ class NotificationManagementServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new NotificationManagementService; + $service = new NotificationManagementService(); $result = $service->update(1, ['title' => 'New']); $this->assertTrue($result['ok']); @@ -35,7 +35,7 @@ class NotificationManagementServiceTest extends TestCase public function test_update_returns_false_when_missing(): void { - $service = new NotificationManagementService; + $service = new NotificationManagementService(); $result = $service->update(999, ['title' => 'New']); $this->assertFalse($result['ok']); @@ -53,7 +53,7 @@ class NotificationManagementServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new NotificationManagementService; + $service = new NotificationManagementService(); $this->assertTrue($service->delete(1)); $this->assertSoftDeleted('notifications', ['id' => 1]); diff --git a/tests/Unit/Services/Notifications/NotificationReadServiceTest.php b/tests/Unit/Services/Notifications/NotificationReadServiceTest.php index de459ad5..5506cbaf 100644 --- a/tests/Unit/Services/Notifications/NotificationReadServiceTest.php +++ b/tests/Unit/Services/Notifications/NotificationReadServiceTest.php @@ -19,7 +19,7 @@ class NotificationReadServiceTest extends TestCase 'is_read' => 0, ]); - $service = new NotificationReadService; + $service = new NotificationReadService(); $result = $service->markRead(1, 1); $this->assertTrue($result); @@ -32,7 +32,7 @@ class NotificationReadServiceTest extends TestCase public function test_mark_read_returns_false_when_missing(): void { - $service = new NotificationReadService; + $service = new NotificationReadService(); $this->assertFalse($service->markRead(1, 99)); } diff --git a/tests/Unit/Services/Notifications/NotificationRecipientServiceTest.php b/tests/Unit/Services/Notifications/NotificationRecipientServiceTest.php index 7e94c4a0..338d4e2b 100644 --- a/tests/Unit/Services/Notifications/NotificationRecipientServiceTest.php +++ b/tests/Unit/Services/Notifications/NotificationRecipientServiceTest.php @@ -46,7 +46,7 @@ class NotificationRecipientServiceTest extends TestCase 'role_id' => 1, ]); - $service = new NotificationRecipientService; + $service = new NotificationRecipientService(); $rows = $service->getRecipients('parent'); $this->assertCount(1, $rows); diff --git a/tests/Unit/Services/Notifications/NotificationShowServiceTest.php b/tests/Unit/Services/Notifications/NotificationShowServiceTest.php index a28194a2..38650730 100644 --- a/tests/Unit/Services/Notifications/NotificationShowServiceTest.php +++ b/tests/Unit/Services/Notifications/NotificationShowServiceTest.php @@ -30,7 +30,7 @@ class NotificationShowServiceTest extends TestCase 'is_read' => 0, ]); - $service = new NotificationShowService; + $service = new NotificationShowService(); $row = $service->getForUser(1, 1); $this->assertNotNull($row); @@ -39,7 +39,7 @@ class NotificationShowServiceTest extends TestCase public function test_get_for_user_returns_null_when_missing(): void { - $service = new NotificationShowService; + $service = new NotificationShowService(); $row = $service->getForUser(1, 99); $this->assertNull($row); diff --git a/tests/Unit/Services/Notifications/NotificationUserListServiceTest.php b/tests/Unit/Services/Notifications/NotificationUserListServiceTest.php index 14e3491e..b3709f3b 100644 --- a/tests/Unit/Services/Notifications/NotificationUserListServiceTest.php +++ b/tests/Unit/Services/Notifications/NotificationUserListServiceTest.php @@ -49,7 +49,7 @@ class NotificationUserListServiceTest extends TestCase ], ]); - $service = new NotificationUserListService; + $service = new NotificationUserListService(); $result = $service->listForUser(1, [ 'read' => true, 'per_page' => 10, diff --git a/tests/Unit/Services/Notifications/UserNotificationDispatchServiceTest.php b/tests/Unit/Services/Notifications/UserNotificationDispatchServiceTest.php index d59d9b1c..5b024cbb 100644 --- a/tests/Unit/Services/Notifications/UserNotificationDispatchServiceTest.php +++ b/tests/Unit/Services/Notifications/UserNotificationDispatchServiceTest.php @@ -34,7 +34,7 @@ class UserNotificationDispatchServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new UserNotificationDispatchService; + $service = new UserNotificationDispatchService(); $result = $service->notifyUser(1, 'Title', 'Message', ['in_app'], 'registration', 'parent'); $this->assertTrue($result['ok']); @@ -50,7 +50,7 @@ class UserNotificationDispatchServiceTest extends TestCase public function test_notify_user_rejects_invalid_user(): void { - $service = new UserNotificationDispatchService; + $service = new UserNotificationDispatchService(); $result = $service->notifyUser(0, 'Title', 'Message'); $this->assertFalse($result['ok']); diff --git a/tests/Unit/Services/Parents/ParentAttendanceReportServiceTest.php b/tests/Unit/Services/Parents/ParentAttendanceReportServiceTest.php index 326e42d0..3321c784 100644 --- a/tests/Unit/Services/Parents/ParentAttendanceReportServiceTest.php +++ b/tests/Unit/Services/Parents/ParentAttendanceReportServiceTest.php @@ -25,9 +25,9 @@ class ParentAttendanceReportServiceTest extends TestCase $this->seedStudent($parentId); $service = new ParentAttendanceReportService( - new ParentConfigService, - new ParentAttendanceReportCalendarService(new ParentConfigService), - new SemesterRangeService(new SemesterConfigService) + new ParentConfigService(), + new ParentAttendanceReportCalendarService(new ParentConfigService()), + new SemesterRangeService(new SemesterConfigService()) ); $data = $service->formData($parentId); diff --git a/tests/Unit/Services/Parents/ParentAttendanceServiceTest.php b/tests/Unit/Services/Parents/ParentAttendanceServiceTest.php index b9dd229e..7ed2a824 100644 --- a/tests/Unit/Services/Parents/ParentAttendanceServiceTest.php +++ b/tests/Unit/Services/Parents/ParentAttendanceServiceTest.php @@ -2,6 +2,7 @@ namespace Tests\Unit\Services\Parents; +use App\Models\User; use App\Services\Parents\ParentAttendanceService; use App\Services\Parents\ParentConfigService; use Illuminate\Foundation\Testing\RefreshDatabase; @@ -63,7 +64,7 @@ class ParentAttendanceServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new ParentAttendanceService(new ParentConfigService); + $service = new ParentAttendanceService(new ParentConfigService()); $result = $service->listAttendance($parentId, '2025-2026'); $this->assertSame('2025-2026', $result['selectedYear']); diff --git a/tests/Unit/Services/Parents/ParentConfigServiceTest.php b/tests/Unit/Services/Parents/ParentConfigServiceTest.php index 839eeda0..3bf0c70d 100644 --- a/tests/Unit/Services/Parents/ParentConfigServiceTest.php +++ b/tests/Unit/Services/Parents/ParentConfigServiceTest.php @@ -24,7 +24,7 @@ class ParentConfigServiceTest extends TestCase ['config_key' => 'fall_semester_start', 'config_value' => '2025-09-05'], ]); - $service = new ParentConfigService; + $service = new ParentConfigService(); $context = $service->context(); $this->assertSame('2025-2026', $context['school_year']); diff --git a/tests/Unit/Services/Parents/ParentEmergencyContactServiceTest.php b/tests/Unit/Services/Parents/ParentEmergencyContactServiceTest.php index bf662c44..c6bf969c 100644 --- a/tests/Unit/Services/Parents/ParentEmergencyContactServiceTest.php +++ b/tests/Unit/Services/Parents/ParentEmergencyContactServiceTest.php @@ -18,7 +18,7 @@ class ParentEmergencyContactServiceTest extends TestCase $this->seedConfig(); $parentId = $this->seedParent(); - $service = new ParentEmergencyContactService(new ParentConfigService, new PhoneFormatterService); + $service = new ParentEmergencyContactService(new ParentConfigService(), new PhoneFormatterService()); $contact = $service->store($parentId, [ 'name' => 'Sam Contact', 'cellphone' => '1234567890', diff --git a/tests/Unit/Services/Parents/ParentEnrollmentServiceTest.php b/tests/Unit/Services/Parents/ParentEnrollmentServiceTest.php index 07a467f0..83b0aa1c 100644 --- a/tests/Unit/Services/Parents/ParentEnrollmentServiceTest.php +++ b/tests/Unit/Services/Parents/ParentEnrollmentServiceTest.php @@ -42,7 +42,7 @@ class ParentEnrollmentServiceTest extends TestCase 'is_withdrawn' => 0, ]); - $service = new ParentEnrollmentService(new ParentConfigService); + $service = new ParentEnrollmentService(new ParentConfigService()); $result = $service->overview($parentId, '2025-2026'); $this->assertSame('2025-2026', $result['selectedYear']); diff --git a/tests/Unit/Services/Parents/ParentInvoiceServiceTest.php b/tests/Unit/Services/Parents/ParentInvoiceServiceTest.php index 59961f00..510a736c 100644 --- a/tests/Unit/Services/Parents/ParentInvoiceServiceTest.php +++ b/tests/Unit/Services/Parents/ParentInvoiceServiceTest.php @@ -34,7 +34,7 @@ class ParentInvoiceServiceTest extends TestCase 'issue_date' => '2025-09-02', ]); - $service = new ParentInvoiceService; + $service = new ParentInvoiceService(); $rows = $service->listInvoices($parentId); $this->assertCount(1, $rows); diff --git a/tests/Unit/Services/Parents/ParentRegistrationServiceTest.php b/tests/Unit/Services/Parents/ParentRegistrationServiceTest.php index a34842e4..fbb9eecd 100644 --- a/tests/Unit/Services/Parents/ParentRegistrationServiceTest.php +++ b/tests/Unit/Services/Parents/ParentRegistrationServiceTest.php @@ -18,7 +18,7 @@ class ParentRegistrationServiceTest extends TestCase $this->seedConfig(); $parentId = $this->seedParent(); - $service = new ParentRegistrationService(new ParentConfigService, new SchoolIdService); + $service = new ParentRegistrationService(new ParentConfigService(), new SchoolIdService()); $result = $service->register($parentId, [ [ 'firstname' => 'Omar', diff --git a/tests/Unit/Services/Payments/PaymentBalanceServiceTest.php b/tests/Unit/Services/Payments/PaymentBalanceServiceTest.php index 87e71d1b..5fa4e6d7 100644 --- a/tests/Unit/Services/Payments/PaymentBalanceServiceTest.php +++ b/tests/Unit/Services/Payments/PaymentBalanceServiceTest.php @@ -27,7 +27,7 @@ class PaymentBalanceServiceTest extends TestCase 'status' => 'Pending', ]); - $service = new PaymentBalanceService; + $service = new PaymentBalanceService(); $updated = $service->updateBalance(1, 40); $this->assertTrue($updated); diff --git a/tests/Unit/Services/Payments/PaymentEnrollmentEventServiceTest.php b/tests/Unit/Services/Payments/PaymentEnrollmentEventServiceTest.php index 12b0890c..4225103d 100644 --- a/tests/Unit/Services/Payments/PaymentEnrollmentEventServiceTest.php +++ b/tests/Unit/Services/Payments/PaymentEnrollmentEventServiceTest.php @@ -14,7 +14,7 @@ class PaymentEnrollmentEventServiceTest extends TestCase private function makeService(): PaymentEnrollmentEventService { - return new PaymentEnrollmentEventService(new ApplicationUrlService); + return new PaymentEnrollmentEventService(new ApplicationUrlService()); } public function test_build_event_data_requires_parent(): void diff --git a/tests/Unit/Services/Payments/PaymentLookupServiceTest.php b/tests/Unit/Services/Payments/PaymentLookupServiceTest.php index 03afbc4b..a47e0fd1 100644 --- a/tests/Unit/Services/Payments/PaymentLookupServiceTest.php +++ b/tests/Unit/Services/Payments/PaymentLookupServiceTest.php @@ -41,7 +41,7 @@ class PaymentLookupServiceTest extends TestCase 'status' => 'Pending', ]); - $service = new PaymentLookupService; + $service = new PaymentLookupService(); $results = $service->getByParent(10, '2025-2026'); $this->assertCount(1, $results); diff --git a/tests/Unit/Services/Payments/PaymentNotificationDispatchServiceTest.php b/tests/Unit/Services/Payments/PaymentNotificationDispatchServiceTest.php index 07345f48..74b9c2ba 100644 --- a/tests/Unit/Services/Payments/PaymentNotificationDispatchServiceTest.php +++ b/tests/Unit/Services/Payments/PaymentNotificationDispatchServiceTest.php @@ -18,7 +18,7 @@ class PaymentNotificationDispatchServiceTest extends TestCase ['id' => 2002, 'config_key' => 'semester', 'config_value' => 'Fall'], ]); - $service = new PaymentNotificationDispatchService; + $service = new PaymentNotificationDispatchService(); $service->notifyUser(10, 'Payment Reminder', 'Reminder body', ['in_app']); $this->assertDatabaseHas('notifications', [ diff --git a/tests/Unit/Services/Payments/PaymentPlanServiceTest.php b/tests/Unit/Services/Payments/PaymentPlanServiceTest.php index 489dcd70..119ffa30 100644 --- a/tests/Unit/Services/Payments/PaymentPlanServiceTest.php +++ b/tests/Unit/Services/Payments/PaymentPlanServiceTest.php @@ -53,7 +53,7 @@ class PaymentPlanServiceTest extends TestCase 'semester' => 'Fall', ]); - $service = new PaymentPlanService; + $service = new PaymentPlanService(); $payment = $service->createPlan([ 'parent_id' => 10, 'invoice_id' => 1, diff --git a/tests/Unit/Services/Payments/PaymentTransactionServiceTest.php b/tests/Unit/Services/Payments/PaymentTransactionServiceTest.php index 9551e94d..aaf648ea 100644 --- a/tests/Unit/Services/Payments/PaymentTransactionServiceTest.php +++ b/tests/Unit/Services/Payments/PaymentTransactionServiceTest.php @@ -3,8 +3,8 @@ namespace Tests\Unit\Services\Payments; use App\Services\Payments\PaymentTransactionService; -use Illuminate\Database\Schema\Blueprint; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Tests\TestCase; @@ -15,13 +15,13 @@ class PaymentTransactionServiceTest extends TestCase public function test_create_and_update_transaction(): void { - if (! Schema::hasColumn('payment_transactions', 'payment_reference')) { + if (!Schema::hasColumn('payment_transactions', 'payment_reference')) { Schema::table('payment_transactions', function (Blueprint $table) { $table->string('payment_reference')->nullable(); }); } - if (! Schema::hasColumn('payment_transactions', 'is_full_payment')) { + if (!Schema::hasColumn('payment_transactions', 'is_full_payment')) { Schema::table('payment_transactions', function (Blueprint $table) { $table->boolean('is_full_payment')->default(0); }); @@ -41,7 +41,7 @@ class PaymentTransactionServiceTest extends TestCase 'status' => 'Pending', ]); - $service = new PaymentTransactionService; + $service = new PaymentTransactionService(); $transaction = $service->create([ 'transaction_id' => 'TXN-1', 'payment_id' => 1, diff --git a/tests/Unit/Services/Payments/PaypalPaymentServiceTest.php b/tests/Unit/Services/Payments/PaypalPaymentServiceTest.php index a52fd31c..a7a93778 100644 --- a/tests/Unit/Services/Payments/PaypalPaymentServiceTest.php +++ b/tests/Unit/Services/Payments/PaypalPaymentServiceTest.php @@ -14,7 +14,7 @@ class PaypalPaymentServiceTest extends TestCase private function makeService(): PaypalPaymentService { - return new PaypalPaymentService(new ApplicationUrlService); + return new PaypalPaymentService(new ApplicationUrlService()); } public function test_create_payment_falls_back_to_hosted_when_sdk_missing(): void diff --git a/tests/Unit/Services/Payments/PaypalTransactionsServiceTest.php b/tests/Unit/Services/Payments/PaypalTransactionsServiceTest.php index 9457959c..2e2759fb 100644 --- a/tests/Unit/Services/Payments/PaypalTransactionsServiceTest.php +++ b/tests/Unit/Services/Payments/PaypalTransactionsServiceTest.php @@ -37,7 +37,7 @@ class PaypalTransactionsServiceTest extends TestCase 'created_at' => '2025-01-02 00:00:00', ]); - $service = new PaypalTransactionsService; + $service = new PaypalTransactionsService(); $results = $service->listAll('ABC'); $this->assertCount(1, $results); diff --git a/tests/Unit/Services/Policy/PolicyContentServiceTest.php b/tests/Unit/Services/Policy/PolicyContentServiceTest.php index 702c1266..1c12b85a 100644 --- a/tests/Unit/Services/Policy/PolicyContentServiceTest.php +++ b/tests/Unit/Services/Policy/PolicyContentServiceTest.php @@ -12,7 +12,7 @@ class PolicyContentServiceTest extends TestCase public function test_get_policy_returns_content(): void { - $service = new PolicyContentService; + $service = new PolicyContentService(); $result = $service->getPolicy('school'); $this->assertSame('school', $result['type']); diff --git a/tests/Unit/Services/Promotions/LevelProgressionServiceTest.php b/tests/Unit/Services/Promotions/LevelProgressionServiceTest.php index 58e1dc0b..f20daddd 100644 --- a/tests/Unit/Services/Promotions/LevelProgressionServiceTest.php +++ b/tests/Unit/Services/Promotions/LevelProgressionServiceTest.php @@ -14,7 +14,7 @@ class LevelProgressionServiceTest extends TestCase public function test_seed_defaults_creates_baseline_levels(): void { - $service = new LevelProgressionService; + $service = new LevelProgressionService(); $created = $service->seedDefaults(); $this->assertGreaterThan(0, $created); $this->assertSame($created, LevelProgression::query()->count()); @@ -35,7 +35,7 @@ class LevelProgressionServiceTest extends TestCase ['id' => 8, 'class_name' => 'Grade 4', 'school_year' => '2025-2026', 'semester' => 'Fall', 'capacity' => 0], ]); - $service = new LevelProgressionService; + $service = new LevelProgressionService(); $service->seedDefaults(); $resolved = $service->resolveByCurrentClassId(7); @@ -53,7 +53,7 @@ class LevelProgressionServiceTest extends TestCase ['id' => 101, 'class_name' => 'Custom B', 'school_year' => '2025-2026', 'semester' => 'Fall', 'capacity' => 0], ]); - $service = new LevelProgressionService; + $service = new LevelProgressionService(); $resolved = $service->resolveByCurrentClassId(100); $this->assertNotNull($resolved); @@ -64,7 +64,7 @@ class LevelProgressionServiceTest extends TestCase public function test_upsert_mapping_updates_existing_row(): void { - $service = new LevelProgressionService; + $service = new LevelProgressionService(); $service->upsertMapping([ 'current_level_name' => 'Grade 5', 'next_level_name' => 'Grade 6', diff --git a/tests/Unit/Services/Promotions/PromotionEligibilityServiceTest.php b/tests/Unit/Services/Promotions/PromotionEligibilityServiceTest.php index 3f155996..3d34fb9c 100644 --- a/tests/Unit/Services/Promotions/PromotionEligibilityServiceTest.php +++ b/tests/Unit/Services/Promotions/PromotionEligibilityServiceTest.php @@ -2,7 +2,6 @@ namespace Tests\Unit\Services\Promotions; -use App\Models\LevelProgression; use App\Models\StudentPromotionRecord; use App\Services\Promotions\LevelProgressionService; use App\Services\Promotions\PromotionAuditService; @@ -76,7 +75,7 @@ class PromotionEligibilityServiceTest extends TestCase $this->seedDecision($studentId, '2025-2026', 90.0, 'promoted'); // Mark Youth as terminal - LevelProgression::query()->where('current_level_name', 'Youth')->update(['is_terminal' => 1]); + \App\Models\LevelProgression::query()->where('current_level_name', 'Youth')->update(['is_terminal' => 1]); $service = $this->makeService(); $record = $service->evaluateStudent($studentId, '2025-2026', 1); @@ -109,10 +108,9 @@ class PromotionEligibilityServiceTest extends TestCase private function makeService(): PromotionEligibilityService { - $progression = new LevelProgressionService; - $audit = new PromotionAuditService; + $progression = new LevelProgressionService(); + $audit = new PromotionAuditService(); $status = new PromotionStatusService($audit); - return new PromotionEligibilityService($progression, $status, $audit); } @@ -175,4 +173,4 @@ class PromotionEligibilityServiceTest extends TestCase 'updated_at' => now(), ]); } -} +} \ No newline at end of file diff --git a/tests/Unit/Services/Promotions/PromotionEnrollmentServiceTest.php b/tests/Unit/Services/Promotions/PromotionEnrollmentServiceTest.php index 27c627c8..efa98d9c 100644 --- a/tests/Unit/Services/Promotions/PromotionEnrollmentServiceTest.php +++ b/tests/Unit/Services/Promotions/PromotionEnrollmentServiceTest.php @@ -100,7 +100,7 @@ class PromotionEnrollmentServiceTest extends TestCase */ private function bootstrap(): array { - $audit = new PromotionAuditService; + $audit = new PromotionAuditService(); $service = new PromotionEnrollmentService(new PromotionStatusService($audit), $audit); $parentId = (int) DB::table('users')->insertGetId([ diff --git a/tests/Unit/Services/Promotions/PromotionStatusServiceTest.php b/tests/Unit/Services/Promotions/PromotionStatusServiceTest.php index b21db466..c4e157f6 100644 --- a/tests/Unit/Services/Promotions/PromotionStatusServiceTest.php +++ b/tests/Unit/Services/Promotions/PromotionStatusServiceTest.php @@ -82,7 +82,7 @@ class PromotionStatusServiceTest extends TestCase private function makeService(): PromotionStatusService { - return new PromotionStatusService(new PromotionAuditService); + return new PromotionStatusService(new PromotionAuditService()); } private function makeRecord(string $status): StudentPromotionRecord diff --git a/tests/Unit/Services/PurchaseOrders/PurchaseOrderCreateServiceTest.php b/tests/Unit/Services/PurchaseOrders/PurchaseOrderCreateServiceTest.php index adc7a63d..332dd0ab 100644 --- a/tests/Unit/Services/PurchaseOrders/PurchaseOrderCreateServiceTest.php +++ b/tests/Unit/Services/PurchaseOrders/PurchaseOrderCreateServiceTest.php @@ -16,7 +16,7 @@ class PurchaseOrderCreateServiceTest extends TestCase $supplierId = DB::table('suppliers')->insertGetId(['name' => 'Alpha Supplies']); $supplyId = DB::table('supplies')->insertGetId(['name' => 'Paper', 'unit' => 'box', 'qty_on_hand' => 0]); - $service = new PurchaseOrderCreateService; + $service = new PurchaseOrderCreateService(); $po = $service->create([ 'po_number' => 'PO-500', 'supplier_id' => $supplierId, diff --git a/tests/Unit/Services/PurchaseOrders/PurchaseOrderReceiveServiceTest.php b/tests/Unit/Services/PurchaseOrders/PurchaseOrderReceiveServiceTest.php index 8cce2db6..f560dd72 100644 --- a/tests/Unit/Services/PurchaseOrders/PurchaseOrderReceiveServiceTest.php +++ b/tests/Unit/Services/PurchaseOrders/PurchaseOrderReceiveServiceTest.php @@ -39,7 +39,7 @@ class PurchaseOrderReceiveServiceTest extends TestCase 'unit_cost' => 3, ]); - $service = new PurchaseOrderReceiveService; + $service = new PurchaseOrderReceiveService(); $result = $service->receive($po->id, [ ['id' => $item->id, 'quantity' => 3], ], 'tester@example.com'); diff --git a/tests/Unit/Services/PurchaseOrders/PurchaseOrderStatusServiceTest.php b/tests/Unit/Services/PurchaseOrders/PurchaseOrderStatusServiceTest.php index 33e0e63c..37d0532c 100644 --- a/tests/Unit/Services/PurchaseOrders/PurchaseOrderStatusServiceTest.php +++ b/tests/Unit/Services/PurchaseOrders/PurchaseOrderStatusServiceTest.php @@ -22,7 +22,7 @@ class PurchaseOrderStatusServiceTest extends TestCase 'total' => 0, ]); - $service = new PurchaseOrderStatusService; + $service = new PurchaseOrderStatusService(); $updated = $service->cancel($po->id); $this->assertSame(PurchaseOrder::STATUS_CANCELED, $updated->status); diff --git a/tests/Unit/Services/Refunds/RefundDecisionServiceTest.php b/tests/Unit/Services/Refunds/RefundDecisionServiceTest.php index 5842e1ec..298f6054 100644 --- a/tests/Unit/Services/Refunds/RefundDecisionServiceTest.php +++ b/tests/Unit/Services/Refunds/RefundDecisionServiceTest.php @@ -26,7 +26,7 @@ class RefundDecisionServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new RefundDecisionService; + $service = new RefundDecisionService(); $result = $service->approve(1, 2); $this->assertTrue($result['ok']); diff --git a/tests/Unit/Services/Refunds/RefundNotificationServiceTest.php b/tests/Unit/Services/Refunds/RefundNotificationServiceTest.php index ef0a8957..4e687932 100644 --- a/tests/Unit/Services/Refunds/RefundNotificationServiceTest.php +++ b/tests/Unit/Services/Refunds/RefundNotificationServiceTest.php @@ -15,7 +15,7 @@ class RefundNotificationServiceTest extends TestCase { Log::spy(); - $service = new RefundNotificationService; + $service = new RefundNotificationService(); $service->notifyPending(10, 50.25, 'https://example.test/login'); Log::shouldHaveReceived('info')->once(); diff --git a/tests/Unit/Services/Refunds/RefundOverpaymentServiceTest.php b/tests/Unit/Services/Refunds/RefundOverpaymentServiceTest.php index c6ee418f..7b648b67 100644 --- a/tests/Unit/Services/Refunds/RefundOverpaymentServiceTest.php +++ b/tests/Unit/Services/Refunds/RefundOverpaymentServiceTest.php @@ -45,7 +45,7 @@ class RefundOverpaymentServiceTest extends TestCase 'status' => 'Paid', ]); - $service = new RefundOverpaymentService(new RefundNotificationService); + $service = new RefundOverpaymentService(new RefundNotificationService()); $result = $service->recalculate(false, null, 1); $this->assertNotEmpty($result['created_ids']); diff --git a/tests/Unit/Services/Refunds/RefundPayoutServiceTest.php b/tests/Unit/Services/Refunds/RefundPayoutServiceTest.php index 2ad40c0f..5c5cf9cf 100644 --- a/tests/Unit/Services/Refunds/RefundPayoutServiceTest.php +++ b/tests/Unit/Services/Refunds/RefundPayoutServiceTest.php @@ -27,7 +27,7 @@ class RefundPayoutServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new RefundPayoutService; + $service = new RefundPayoutService(); $result = $service->recordPayment(1, [ 'paid_amount' => 40, 'payment_method' => 'Cash', diff --git a/tests/Unit/Services/Refunds/RefundPolicyServiceTest.php b/tests/Unit/Services/Refunds/RefundPolicyServiceTest.php index 6d4ecd1a..593e1c63 100644 --- a/tests/Unit/Services/Refunds/RefundPolicyServiceTest.php +++ b/tests/Unit/Services/Refunds/RefundPolicyServiceTest.php @@ -2,10 +2,10 @@ namespace Tests\Unit\Services\Refunds; -use App\Services\Discounts\DiscountInvoiceService; -use App\Services\Fees\FeeRefundDetailService; use App\Services\Refunds\RefundInvoiceAdjustmentService; use App\Services\Refunds\RefundPolicyService; +use App\Services\Fees\FeeRefundDetailService; +use App\Services\Discounts\DiscountInvoiceService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; use Tests\TestCase; @@ -84,8 +84,8 @@ class RefundPolicyServiceTest extends TestCase ]); $service = new RefundPolicyService( - new FeeRefundDetailService, - new RefundInvoiceAdjustmentService(new DiscountInvoiceService) + new FeeRefundDetailService(), + new RefundInvoiceAdjustmentService(new DiscountInvoiceService()) ); $result = $service->processWithdrawalRefund(10, 1, '2025-2026', 'Fall', 1); diff --git a/tests/Unit/Services/Refunds/RefundQueryServiceTest.php b/tests/Unit/Services/Refunds/RefundQueryServiceTest.php index 90de4355..3e144468 100644 --- a/tests/Unit/Services/Refunds/RefundQueryServiceTest.php +++ b/tests/Unit/Services/Refunds/RefundQueryServiceTest.php @@ -40,7 +40,7 @@ class RefundQueryServiceTest extends TestCase ], ]); - $service = new RefundQueryService; + $service = new RefundQueryService(); $result = $service->list(['status' => 'Approved', 'per_page' => 10, 'page' => 1]); $this->assertSame(1, $result['pagination']['total']); diff --git a/tests/Unit/Services/Refunds/RefundRequestServiceTest.php b/tests/Unit/Services/Refunds/RefundRequestServiceTest.php index 12f97147..4ec216a9 100644 --- a/tests/Unit/Services/Refunds/RefundRequestServiceTest.php +++ b/tests/Unit/Services/Refunds/RefundRequestServiceTest.php @@ -2,13 +2,13 @@ namespace Tests\Unit\Services\Refunds; -use App\Services\Discounts\DiscountInvoiceService; use App\Services\Fees\FeeRefundDetailService; use App\Services\Refunds\RefundInvoiceAdjustmentService; use App\Services\Refunds\RefundNotificationService; use App\Services\Refunds\RefundPolicyService; use App\Services\Refunds\RefundRequestService; use App\Services\Refunds\RefundSummaryService; +use App\Services\Discounts\DiscountInvoiceService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; use Tests\TestCase; @@ -60,11 +60,11 @@ class RefundRequestServiceTest extends TestCase $service = new RefundRequestService( new RefundPolicyService( - new FeeRefundDetailService, - new RefundInvoiceAdjustmentService(new DiscountInvoiceService) + new FeeRefundDetailService(), + new RefundInvoiceAdjustmentService(new DiscountInvoiceService()) ), - new RefundSummaryService, - new RefundNotificationService + new RefundSummaryService(), + new RefundNotificationService() ); $result = $service->requestRefund([ diff --git a/tests/Unit/Services/Refunds/RefundSummaryServiceTest.php b/tests/Unit/Services/Refunds/RefundSummaryServiceTest.php index 582c9dd2..04cfb10b 100644 --- a/tests/Unit/Services/Refunds/RefundSummaryServiceTest.php +++ b/tests/Unit/Services/Refunds/RefundSummaryServiceTest.php @@ -53,7 +53,7 @@ class RefundSummaryServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new RefundSummaryService; + $service = new RefundSummaryService(); $summary = $service->getParentFinancialSummary(10, '2025-2026', 'Fall'); $this->assertSame(100.0, $summary['total_invoiced']); diff --git a/tests/Unit/Services/Reimbursements/ReimbursementBatchAssignmentServiceTest.php b/tests/Unit/Services/Reimbursements/ReimbursementBatchAssignmentServiceTest.php index c3bb951f..7d4e2ee5 100644 --- a/tests/Unit/Services/Reimbursements/ReimbursementBatchAssignmentServiceTest.php +++ b/tests/Unit/Services/Reimbursements/ReimbursementBatchAssignmentServiceTest.php @@ -54,7 +54,7 @@ class ReimbursementBatchAssignmentServiceTest extends TestCase 'status' => 'approved', ]); - $service = new ReimbursementBatchAssignmentService(new ReimbursementLookupService); + $service = new ReimbursementBatchAssignmentService(new ReimbursementLookupService()); $result = $service->updateAssignment(100, 10, 1, null, '2025-2026', 'Fall'); $this->assertSame(10, $result['batch_id']); diff --git a/tests/Unit/Services/Reimbursements/ReimbursementBatchServiceTest.php b/tests/Unit/Services/Reimbursements/ReimbursementBatchServiceTest.php index aea494f5..632d2bed 100644 --- a/tests/Unit/Services/Reimbursements/ReimbursementBatchServiceTest.php +++ b/tests/Unit/Services/Reimbursements/ReimbursementBatchServiceTest.php @@ -13,7 +13,7 @@ class ReimbursementBatchServiceTest extends TestCase public function test_create_batch_assigns_sequence_and_title(): void { - $service = new ReimbursementBatchService(new ReimbursementLookupService); + $service = new ReimbursementBatchService(new ReimbursementLookupService()); $batch = $service->createBatch(null, 1, '2025-2026', 'Fall'); diff --git a/tests/Unit/Services/Reimbursements/ReimbursementDonationServiceTest.php b/tests/Unit/Services/Reimbursements/ReimbursementDonationServiceTest.php index 14136f1c..a6a1cbcc 100644 --- a/tests/Unit/Services/Reimbursements/ReimbursementDonationServiceTest.php +++ b/tests/Unit/Services/Reimbursements/ReimbursementDonationServiceTest.php @@ -59,7 +59,7 @@ class ReimbursementDonationServiceTest extends TestCase 'assigned_at' => now(), ]); - $service = new ReimbursementDonationService; + $service = new ReimbursementDonationService(); $service->markDonation(200, 1); $this->assertDatabaseHas('expenses', [ diff --git a/tests/Unit/Services/Reimbursements/ReimbursementRecipientServiceTest.php b/tests/Unit/Services/Reimbursements/ReimbursementRecipientServiceTest.php index b33e3140..a9665b59 100644 --- a/tests/Unit/Services/Reimbursements/ReimbursementRecipientServiceTest.php +++ b/tests/Unit/Services/Reimbursements/ReimbursementRecipientServiceTest.php @@ -66,7 +66,7 @@ class ReimbursementRecipientServiceTest extends TestCase ['user_id' => 2, 'role_id' => 2], ]); - $service = new ReimbursementRecipientService; + $service = new ReimbursementRecipientService(); $recipients = $service->recipientOptions(); $ids = array_map(static fn ($row) => (int) ($row['id'] ?? 0), $recipients); diff --git a/tests/Unit/Services/Reports/ReportCards/ReportCardServiceTest.php b/tests/Unit/Services/Reports/ReportCards/ReportCardServiceTest.php index d87395b4..b5f9d6d1 100644 --- a/tests/Unit/Services/Reports/ReportCards/ReportCardServiceTest.php +++ b/tests/Unit/Services/Reports/ReportCards/ReportCardServiceTest.php @@ -16,7 +16,7 @@ class ReportCardServiceTest extends TestCase $this->seedConfig(); $this->seedReportCardData(); - $service = new ReportCardService; + $service = new ReportCardService(); $result = $service->meta('2025-2026', 'Fall'); $this->assertNotEmpty($result['schoolYears']); @@ -30,7 +30,7 @@ class ReportCardServiceTest extends TestCase $this->seedConfig(); $data = $this->seedReportCardData(); - $service = new ReportCardService; + $service = new ReportCardService(); $result = $service->completeness('2025-2026', 'Fall', $data['class_section_id']); $this->assertTrue($result['ok']); @@ -44,7 +44,7 @@ class ReportCardServiceTest extends TestCase $data = $this->seedReportCardData(); $this->seedAcknowledgement($data['student_id']); - $service = new ReportCardService; + $service = new ReportCardService(); $result = $service->acknowledgement($data['student_id'], '2025-2026', 'Fall'); $this->assertSame('Parent One', $result['signed_name']); @@ -55,7 +55,7 @@ class ReportCardServiceTest extends TestCase $this->seedConfig(); $data = $this->seedReportCardData(); - $service = new ReportCardService; + $service = new ReportCardService(); $result = $service->generateSingleReport($data['student_id'], [ 'school_year' => '2025-2026', 'semester' => 'Fall', @@ -71,7 +71,7 @@ class ReportCardServiceTest extends TestCase $this->seedConfig(); $studentId = $this->seedStudentOnly(); - $service = new ReportCardService; + $service = new ReportCardService(); $result = $service->generateSingleReport($studentId, [ 'school_year' => '2025-2026', 'semester' => 'Fall', diff --git a/tests/Unit/Services/Reports/SlipPrinterFormatterServiceTest.php b/tests/Unit/Services/Reports/SlipPrinterFormatterServiceTest.php index 6690d156..f15deeb5 100644 --- a/tests/Unit/Services/Reports/SlipPrinterFormatterServiceTest.php +++ b/tests/Unit/Services/Reports/SlipPrinterFormatterServiceTest.php @@ -9,13 +9,13 @@ class SlipPrinterFormatterServiceTest extends TestCase { public function test_to_db_date_parses_us_format(): void { - $service = new SlipPrinterFormatterService; + $service = new SlipPrinterFormatterService(); $this->assertSame('2025-09-01', $service->toDbDate('09/01/2025')); } public function test_to_db_time_parses_string(): void { - $service = new SlipPrinterFormatterService; + $service = new SlipPrinterFormatterService(); $this->assertSame('08:15:00', $service->toDbTime('8:15 AM')); } } diff --git a/tests/Unit/Services/Reports/Stickers/StickerPresetServiceTest.php b/tests/Unit/Services/Reports/Stickers/StickerPresetServiceTest.php index 041e5e0b..f1aeaa7c 100644 --- a/tests/Unit/Services/Reports/Stickers/StickerPresetServiceTest.php +++ b/tests/Unit/Services/Reports/Stickers/StickerPresetServiceTest.php @@ -9,7 +9,7 @@ class StickerPresetServiceTest extends TestCase { public function test_presets_include_alias_fields(): void { - $service = new StickerPresetService; + $service = new StickerPresetService(); $presets = $service->presets(); $this->assertNotEmpty($presets); diff --git a/tests/Unit/Services/Reports/Stickers/StickerPrintServiceTest.php b/tests/Unit/Services/Reports/Stickers/StickerPrintServiceTest.php index 1a6b5096..ac3acb0b 100644 --- a/tests/Unit/Services/Reports/Stickers/StickerPrintServiceTest.php +++ b/tests/Unit/Services/Reports/Stickers/StickerPrintServiceTest.php @@ -16,7 +16,7 @@ class StickerPrintServiceTest extends TestCase public function test_generate_returns_pdf_content(): void { $this->seedData(); - $service = new StickerPrintService(new StickerQueryService(new StickerContextService)); + $service = new StickerPrintService(new StickerQueryService(new StickerContextService())); $result = $service->generate([ 'student_id' => 100, @@ -30,7 +30,7 @@ class StickerPrintServiceTest extends TestCase public function test_generate_returns_error_when_no_students(): void { - $service = new StickerPrintService(new StickerQueryService(new StickerContextService)); + $service = new StickerPrintService(new StickerQueryService(new StickerContextService())); $result = $service->generate([ 'class_section_id' => 999, diff --git a/tests/Unit/Services/Reports/Stickers/StickerQueryServiceTest.php b/tests/Unit/Services/Reports/Stickers/StickerQueryServiceTest.php index 446a532c..95c949fb 100644 --- a/tests/Unit/Services/Reports/Stickers/StickerQueryServiceTest.php +++ b/tests/Unit/Services/Reports/Stickers/StickerQueryServiceTest.php @@ -15,7 +15,7 @@ class StickerQueryServiceTest extends TestCase public function test_list_students_by_class_returns_rows(): void { $this->seedData(); - $service = new StickerQueryService(new StickerContextService); + $service = new StickerQueryService(new StickerContextService()); $students = $service->listStudentsByClass(200, '2025-2026'); @@ -28,7 +28,7 @@ class StickerQueryServiceTest extends TestCase $this->seedData(); $this->seedYouthClass(); - $service = new StickerQueryService(new StickerContextService); + $service = new StickerQueryService(new StickerContextService()); $students = $service->listStudentsForPrintAll('2025-2026'); $this->assertCount(1, $students); diff --git a/tests/Unit/Services/Roles/PermissionCrudServiceTest.php b/tests/Unit/Services/Roles/PermissionCrudServiceTest.php index 34ae85a6..d56462a7 100644 --- a/tests/Unit/Services/Roles/PermissionCrudServiceTest.php +++ b/tests/Unit/Services/Roles/PermissionCrudServiceTest.php @@ -13,7 +13,7 @@ class PermissionCrudServiceTest extends TestCase public function test_create_and_update_permission(): void { - $service = new PermissionCrudService; + $service = new PermissionCrudService(); $permission = $service->create([ 'name' => 'manage_roles', 'description' => 'Manage roles', diff --git a/tests/Unit/Services/Roles/RoleAssignmentServiceTest.php b/tests/Unit/Services/Roles/RoleAssignmentServiceTest.php index efc01a41..e826162d 100644 --- a/tests/Unit/Services/Roles/RoleAssignmentServiceTest.php +++ b/tests/Unit/Services/Roles/RoleAssignmentServiceTest.php @@ -2,6 +2,7 @@ namespace Tests\Unit\Services\Roles; +use App\Models\User; use App\Services\Roles\RoleAssignmentService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; @@ -41,7 +42,7 @@ class RoleAssignmentServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new RoleAssignmentService(new RoleStaffService); + $service = new RoleAssignmentService(new RoleStaffService()); $result = $service->assignRoles($userId, [$roleId], $userId); $this->assertTrue($result['ok']); diff --git a/tests/Unit/Services/Roles/RoleCrudServiceTest.php b/tests/Unit/Services/Roles/RoleCrudServiceTest.php index 551bc851..ad2db6da 100644 --- a/tests/Unit/Services/Roles/RoleCrudServiceTest.php +++ b/tests/Unit/Services/Roles/RoleCrudServiceTest.php @@ -13,7 +13,7 @@ class RoleCrudServiceTest extends TestCase public function test_create_and_update_role(): void { - $service = new RoleCrudService; + $service = new RoleCrudService(); $role = $service->create([ 'name' => 'admin', 'slug' => 'admin', diff --git a/tests/Unit/Services/Roles/RoleDashboardServiceTest.php b/tests/Unit/Services/Roles/RoleDashboardServiceTest.php index c9d0af5d..95933bf9 100644 --- a/tests/Unit/Services/Roles/RoleDashboardServiceTest.php +++ b/tests/Unit/Services/Roles/RoleDashboardServiceTest.php @@ -24,7 +24,7 @@ class RoleDashboardServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new RoleDashboardService; + $service = new RoleDashboardService(); $route = $service->bestDashboardRouteFor(['admin']); $this->assertSame('administrator/administratordashboard', $route); diff --git a/tests/Unit/Services/Roles/RolePermissionServiceTest.php b/tests/Unit/Services/Roles/RolePermissionServiceTest.php index d8a45412..0be8754a 100644 --- a/tests/Unit/Services/Roles/RolePermissionServiceTest.php +++ b/tests/Unit/Services/Roles/RolePermissionServiceTest.php @@ -30,7 +30,7 @@ class RolePermissionServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new RolePermissionService; + $service = new RolePermissionService(); $service->saveRolePermissions($roleId, [ $permissionId => ['create' => true, 'read' => true], ]); diff --git a/tests/Unit/Services/Roles/RoleQueryServiceTest.php b/tests/Unit/Services/Roles/RoleQueryServiceTest.php index ed556dcf..299387a6 100644 --- a/tests/Unit/Services/Roles/RoleQueryServiceTest.php +++ b/tests/Unit/Services/Roles/RoleQueryServiceTest.php @@ -24,7 +24,7 @@ class RoleQueryServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new RoleQueryService; + $service = new RoleQueryService(); $page = $service->listRoles([]); $this->assertCount(1, $page->items()); @@ -65,7 +65,7 @@ class RoleQueryServiceTest extends TestCase 'role_id' => $roleId, ]); - $service = new RoleQueryService; + $service = new RoleQueryService(); $page = $service->listUsersWithRoles([]); $this->assertCount(1, $page->items()); diff --git a/tests/Unit/Services/Roles/RoleSwitchServiceTest.php b/tests/Unit/Services/Roles/RoleSwitchServiceTest.php index 5cef9855..09632972 100644 --- a/tests/Unit/Services/Roles/RoleSwitchServiceTest.php +++ b/tests/Unit/Services/Roles/RoleSwitchServiceTest.php @@ -47,7 +47,7 @@ class RoleSwitchServiceTest extends TestCase 'role_id' => $roleId, ]); - $service = new RoleSwitchService(new RoleDashboardService); + $service = new RoleSwitchService(new RoleDashboardService()); $roles = $service->getUserRoleNames($userId); $this->assertSame(['admin'], $roles); diff --git a/tests/Unit/Services/School/SemesterSelectionServiceTest.php b/tests/Unit/Services/School/SemesterSelectionServiceTest.php index a255f83d..9f997568 100644 --- a/tests/Unit/Services/School/SemesterSelectionServiceTest.php +++ b/tests/Unit/Services/School/SemesterSelectionServiceTest.php @@ -13,7 +13,7 @@ class SemesterSelectionServiceTest extends TestCase public function test_selected_teacher_semester_prefers_session_value(): void { - $service = new SemesterSelectionService; + $service = new SemesterSelectionService(); $this->assertSame('Fall', $service->selectedTeacherSemester()); } @@ -24,7 +24,7 @@ class SemesterSelectionServiceTest extends TestCase ['config_key' => 'semester', 'config_value' => 'Fall'], ]); - $service = new SemesterSelectionService; + $service = new SemesterSelectionService(); $this->assertSame('Fall', $service->selectedTeacherSemester()); } diff --git a/tests/Unit/Services/SchoolIds/SchoolIdGenerationServiceTest.php b/tests/Unit/Services/SchoolIds/SchoolIdGenerationServiceTest.php index 99a21044..4823f673 100644 --- a/tests/Unit/Services/SchoolIds/SchoolIdGenerationServiceTest.php +++ b/tests/Unit/Services/SchoolIds/SchoolIdGenerationServiceTest.php @@ -16,7 +16,7 @@ class SchoolIdGenerationServiceTest extends TestCase $schoolId = $service->generateStudentId(); $year = date('y'); - $this->assertStringStartsWith('STU'.$year, $schoolId); + $this->assertStringStartsWith('STU' . $year, $schoolId); $this->assertSame(10, strlen($schoolId)); } diff --git a/tests/Unit/Services/Scores/AttendanceCalculatorTest.php b/tests/Unit/Services/Scores/AttendanceCalculatorTest.php index f40d1558..9ae89c1e 100644 --- a/tests/Unit/Services/Scores/AttendanceCalculatorTest.php +++ b/tests/Unit/Services/Scores/AttendanceCalculatorTest.php @@ -32,7 +32,7 @@ class AttendanceCalculatorTest extends TestCase 'school_year' => '2024-2025', ]); - $service = new AttendanceCalculator(new AttendanceRecord, new Configuration, new CalendarEvent); + $service = new AttendanceCalculator(new AttendanceRecord(), new Configuration(), new CalendarEvent()); $result = $service->calculate(10, 'Fall', '2024-2025'); $this->assertSame(90.0, $result['attendance_score']); diff --git a/tests/Unit/Services/Scores/ExamScoreServiceTest.php b/tests/Unit/Services/Scores/ExamScoreServiceTest.php index 50f4d27d..991e58a1 100644 --- a/tests/Unit/Services/Scores/ExamScoreServiceTest.php +++ b/tests/Unit/Services/Scores/ExamScoreServiceTest.php @@ -38,7 +38,7 @@ class ExamScoreServiceTest extends TestCase ], ]); - $service = new ExamScoreService(new ScoreTermService); + $service = new ExamScoreService(new ScoreTermService()); $result = $service->list('midterm_exam', 3, 'Fall', '2025-2026'); $this->assertCount(1, $result['students']); @@ -50,7 +50,7 @@ class ExamScoreServiceTest extends TestCase $this->seedStudent(1, 'SCH1', 'Leo', 'Park'); $this->seedStudentClass(1, 3, '2025-2026'); - $service = new ExamScoreService(new ScoreTermService); + $service = new ExamScoreService(new ScoreTermService()); $count = $service->update( 'midterm_exam', diff --git a/tests/Unit/Services/Scores/HomeworkCalculatorTest.php b/tests/Unit/Services/Scores/HomeworkCalculatorTest.php index fef915b5..cb47983f 100644 --- a/tests/Unit/Services/Scores/HomeworkCalculatorTest.php +++ b/tests/Unit/Services/Scores/HomeworkCalculatorTest.php @@ -47,7 +47,7 @@ class HomeworkCalculatorTest extends TestCase ], ]); - $service = new HomeworkCalculator(new Homework); + $service = new HomeworkCalculator(new Homework()); $result = $service->calculate(5, 'Fall', '2024-2025', 1); $this->assertSame(85.0, $result['homework_avg']); diff --git a/tests/Unit/Services/Scores/HomeworkScoreServiceTest.php b/tests/Unit/Services/Scores/HomeworkScoreServiceTest.php index 626ea21d..95bba07d 100644 --- a/tests/Unit/Services/Scores/HomeworkScoreServiceTest.php +++ b/tests/Unit/Services/Scores/HomeworkScoreServiceTest.php @@ -28,7 +28,7 @@ class HomeworkScoreServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new HomeworkScoreService(new ScoreTermService); + $service = new HomeworkScoreService(new ScoreTermService()); $result = $service->list(8, 'Fall', '2025-2026'); $this->assertSame([1], $result['headers']); @@ -40,7 +40,7 @@ class HomeworkScoreServiceTest extends TestCase $this->seedStudent(1, 'SCH1', 'Eli', 'Page'); $this->seedStudentClass(1, 8, '2025-2026'); - $service = new HomeworkScoreService(new ScoreTermService); + $service = new HomeworkScoreService(new ScoreTermService()); $nextIndex = $service->addColumn(8, 'Fall', '2025-2026', 99); diff --git a/tests/Unit/Services/Scores/ParticipationScoreServiceTest.php b/tests/Unit/Services/Scores/ParticipationScoreServiceTest.php index d2b45283..56829a8b 100644 --- a/tests/Unit/Services/Scores/ParticipationScoreServiceTest.php +++ b/tests/Unit/Services/Scores/ParticipationScoreServiceTest.php @@ -28,7 +28,7 @@ class ParticipationScoreServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new ParticipationScoreService(new ScoreTermService); + $service = new ParticipationScoreService(new ScoreTermService()); $result = $service->list(9, 'Fall', '2025-2026'); $this->assertSame(87.0, $result['students'][0]['scores']['score']); @@ -50,7 +50,7 @@ class ParticipationScoreServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new ParticipationScoreService(new ScoreTermService); + $service = new ParticipationScoreService(new ScoreTermService()); $count = $service->update( 9, 'Fall', diff --git a/tests/Unit/Services/Scores/ProjectCalculatorTest.php b/tests/Unit/Services/Scores/ProjectCalculatorTest.php index 1eb2d71d..f1e22a49 100644 --- a/tests/Unit/Services/Scores/ProjectCalculatorTest.php +++ b/tests/Unit/Services/Scores/ProjectCalculatorTest.php @@ -47,7 +47,7 @@ class ProjectCalculatorTest extends TestCase ], ]); - $service = new ProjectCalculator(new Project); + $service = new ProjectCalculator(new Project()); $result = $service->calculate(9, 'Fall', '2024-2025', 1); $this->assertSame(90.0, $result['project_avg']); diff --git a/tests/Unit/Services/Scores/ProjectScoreServiceTest.php b/tests/Unit/Services/Scores/ProjectScoreServiceTest.php index 7c7f11b2..b27c8f7b 100644 --- a/tests/Unit/Services/Scores/ProjectScoreServiceTest.php +++ b/tests/Unit/Services/Scores/ProjectScoreServiceTest.php @@ -28,7 +28,7 @@ class ProjectScoreServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new ProjectScoreService(new ScoreTermService); + $service = new ProjectScoreService(new ScoreTermService()); $result = $service->list(10, 'Fall', '2025-2026'); $this->assertSame([1], $result['headers']); @@ -41,7 +41,7 @@ class ProjectScoreServiceTest extends TestCase $this->seedStudent(1, 'SCH1', 'Maya', 'Stone'); $this->seedStudentClass(1, 10, '2025-2026'); - $service = new ProjectScoreService(new ScoreTermService); + $service = new ProjectScoreService(new ScoreTermService()); $count = $service->update( 10, @@ -73,7 +73,7 @@ class ProjectScoreServiceTest extends TestCase $this->seedStudent(1, 'SCH1', 'Maya', 'Stone'); $this->seedStudentClass(1, 10, '2025-2026'); - $service = new ProjectScoreService(new ScoreTermService); + $service = new ProjectScoreService(new ScoreTermService()); $nextIndex = $service->addColumn(10, 'Fall', '2025-2026', 99); diff --git a/tests/Unit/Services/Scores/QuizCalculatorTest.php b/tests/Unit/Services/Scores/QuizCalculatorTest.php index b53e217d..33dfd0d2 100644 --- a/tests/Unit/Services/Scores/QuizCalculatorTest.php +++ b/tests/Unit/Services/Scores/QuizCalculatorTest.php @@ -56,7 +56,7 @@ class QuizCalculatorTest extends TestCase ], ]); - $service = new QuizCalculator; + $service = new QuizCalculator(); $result = $service->calculate(7, 'Fall', '2024-2025', 2); $this->assertSame(80.0, $result['quiz_avg']); diff --git a/tests/Unit/Services/Scores/QuizScoreServiceTest.php b/tests/Unit/Services/Scores/QuizScoreServiceTest.php index eccdfe42..2be158e8 100644 --- a/tests/Unit/Services/Scores/QuizScoreServiceTest.php +++ b/tests/Unit/Services/Scores/QuizScoreServiceTest.php @@ -28,7 +28,7 @@ class QuizScoreServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new QuizScoreService(new ScoreTermService); + $service = new QuizScoreService(new ScoreTermService()); $result = $service->list(5, 'Fall', '2025-2026'); $this->assertSame([2], $result['headers']); @@ -41,7 +41,7 @@ class QuizScoreServiceTest extends TestCase $this->seedStudent(1, 'SCH1', 'Nina', 'Kim'); $this->seedStudentClass(1, 5, '2025-2026'); - $service = new QuizScoreService(new ScoreTermService); + $service = new QuizScoreService(new ScoreTermService()); $count = $service->update( 5, @@ -73,7 +73,7 @@ class QuizScoreServiceTest extends TestCase $this->seedStudent(1, 'SCH1', 'Nina', 'Kim'); $this->seedStudentClass(1, 5, '2025-2026'); - $service = new QuizScoreService(new ScoreTermService); + $service = new QuizScoreService(new ScoreTermService()); $nextIndex = $service->addColumn(5, 'Fall', '2025-2026', 99); diff --git a/tests/Unit/Services/Scores/ScoreCommentServiceTest.php b/tests/Unit/Services/Scores/ScoreCommentServiceTest.php index 3656e81f..63a13f20 100644 --- a/tests/Unit/Services/Scores/ScoreCommentServiceTest.php +++ b/tests/Unit/Services/Scores/ScoreCommentServiceTest.php @@ -26,7 +26,7 @@ class ScoreCommentServiceTest extends TestCase 'comment' => 'Ava has shown consistent improvement and strong effort across assignments.', ]); - $service = new ScoreCommentService(new ScoreTermService); + $service = new ScoreCommentService(new ScoreTermService()); $result = $service->list('2', 'Fall', '2025-2026'); $this->assertCount(1, $result['students']); @@ -38,7 +38,7 @@ class ScoreCommentServiceTest extends TestCase { $this->seedStudent(1, 'SCH1', 'Ava', 'Lane'); - $service = new ScoreCommentService(new ScoreTermService); + $service = new ScoreCommentService(new ScoreTermService()); $result = $service->save( 2, 'Fall', diff --git a/tests/Unit/Services/Scores/ScoreDashboardServiceTest.php b/tests/Unit/Services/Scores/ScoreDashboardServiceTest.php index 688b098b..bc773bcc 100644 --- a/tests/Unit/Services/Scores/ScoreDashboardServiceTest.php +++ b/tests/Unit/Services/Scores/ScoreDashboardServiceTest.php @@ -39,7 +39,7 @@ class ScoreDashboardServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new ScoreDashboardService(new ScoreTermService); + $service = new ScoreDashboardService(new ScoreTermService()); $result = $service->overview(1, null, 'Fall', '2025-2026'); $this->assertSame(10, $result['class_section_id']); @@ -62,7 +62,7 @@ class ScoreDashboardServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new ScoreDashboardService(new ScoreTermService); + $service = new ScoreDashboardService(new ScoreTermService()); $result = $service->viewStudentScores(7, '2025-2026'); $this->assertArrayHasKey('2025-2026', $result['scores']); diff --git a/tests/Unit/Services/Scores/ScorePredictorServiceTest.php b/tests/Unit/Services/Scores/ScorePredictorServiceTest.php index 7c050d27..fca60523 100644 --- a/tests/Unit/Services/Scores/ScorePredictorServiceTest.php +++ b/tests/Unit/Services/Scores/ScorePredictorServiceTest.php @@ -64,8 +64,8 @@ class ScorePredictorServiceTest extends TestCase ]); $service = new ScorePredictorService( - new ScorePredictorDataService, - new ScorePredictorRiskService + new ScorePredictorDataService(), + new ScorePredictorRiskService() ); $result = $service->report('2025-2026', 1); diff --git a/tests/Unit/Services/Scores/ScoreTermServiceTest.php b/tests/Unit/Services/Scores/ScoreTermServiceTest.php index aa932f92..8c3a6093 100644 --- a/tests/Unit/Services/Scores/ScoreTermServiceTest.php +++ b/tests/Unit/Services/Scores/ScoreTermServiceTest.php @@ -18,7 +18,7 @@ class ScoreTermServiceTest extends TestCase ['config_key' => 'school_year', 'config_value' => '2025-2026'], ]); - $service = new ScoreTermService; + $service = new ScoreTermService(); $this->assertSame('Fall', $service->semesterLabel(null)); $this->assertSame('2025-2026', $service->schoolYear(null)); @@ -26,7 +26,7 @@ class ScoreTermServiceTest extends TestCase public function test_normalize_and_variants(): void { - $service = new ScoreTermService; + $service = new ScoreTermService(); $this->assertSame('fall', $service->normalizeSemester('Semester 1')); $this->assertSame('spring', $service->normalizeSemester('2nd Semester')); diff --git a/tests/Unit/Services/Scores/SemesterScoreServiceTest.php b/tests/Unit/Services/Scores/SemesterScoreServiceTest.php index 39740a91..c699cf76 100644 --- a/tests/Unit/Services/Scores/SemesterScoreServiceTest.php +++ b/tests/Unit/Services/Scores/SemesterScoreServiceTest.php @@ -2,11 +2,11 @@ namespace Tests\Unit\Services\Scores; +use App\Services\Scores\SemesterScoreService; use App\Services\Scores\AttendanceCalculator; use App\Services\Scores\HomeworkCalculator; use App\Services\Scores\ProjectCalculator; use App\Services\Scores\QuizCalculator; -use App\Services\Scores\SemesterScoreService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; use Tests\TestCase; @@ -28,10 +28,10 @@ class SemesterScoreServiceTest extends TestCase ]); $service = new SemesterScoreService( - new FakeAttendanceCalculator, - new FakeHomeworkCalculator, - new FakeQuizCalculator, - new FakeProjectCalculator + new FakeAttendanceCalculator(), + new FakeHomeworkCalculator(), + new FakeQuizCalculator(), + new FakeProjectCalculator() ); $service->updateStudentScores([ @@ -61,7 +61,9 @@ class SemesterScoreServiceTest extends TestCase class FakeAttendanceCalculator extends AttendanceCalculator { - public function __construct() {} + public function __construct() + { + } public function calculate(int $studentId, string $semester, string $schoolYear, ?int $classSectionId = null): array { @@ -71,7 +73,9 @@ class FakeAttendanceCalculator extends AttendanceCalculator class FakeHomeworkCalculator extends HomeworkCalculator { - public function __construct() {} + public function __construct() + { + } public function calculate(int $studentId, string $semester, string $schoolYear, ?int $classSectionId = null): array { @@ -89,7 +93,9 @@ class FakeQuizCalculator extends QuizCalculator class FakeProjectCalculator extends ProjectCalculator { - public function __construct() {} + public function __construct() + { + } public function calculate(int $studentId, string $semester, string $schoolYear, ?int $classSectionId = null): array { diff --git a/tests/Unit/Services/Security/Pbkdf2HasherTest.php b/tests/Unit/Services/Security/Pbkdf2HasherTest.php index c78f2acb..49b7d223 100644 --- a/tests/Unit/Services/Security/Pbkdf2HasherTest.php +++ b/tests/Unit/Services/Security/Pbkdf2HasherTest.php @@ -9,7 +9,7 @@ class Pbkdf2HasherTest extends TestCase { public function test_hash_and_verify(): void { - $hasher = new Pbkdf2Hasher; + $hasher = new Pbkdf2Hasher(); $hash = $hasher->hash('secret'); $this->assertTrue($hasher->verify('secret', $hash)); diff --git a/tests/Unit/Services/Semesters/SemesterConfigServiceTest.php b/tests/Unit/Services/Semesters/SemesterConfigServiceTest.php index 78283d74..9f1976e5 100644 --- a/tests/Unit/Services/Semesters/SemesterConfigServiceTest.php +++ b/tests/Unit/Services/Semesters/SemesterConfigServiceTest.php @@ -19,7 +19,7 @@ class SemesterConfigServiceTest extends TestCase ['id' => 3, 'config_key' => 'last_school_day', 'config_value' => '2026-06-01'], ]); - $service = new SemesterConfigService; + $service = new SemesterConfigService(); $this->assertSame('2025-09-01', $service->getFallStart()?->format('Y-m-d')); $this->assertSame('2026-01-20', $service->getSpringStart()?->format('Y-m-d')); $this->assertSame('2026-06-01', $service->getLastSchoolDay()?->format('Y-m-d')); diff --git a/tests/Unit/Services/Semesters/SemesterRangeServiceTest.php b/tests/Unit/Services/Semesters/SemesterRangeServiceTest.php index b2713c41..58400bff 100644 --- a/tests/Unit/Services/Semesters/SemesterRangeServiceTest.php +++ b/tests/Unit/Services/Semesters/SemesterRangeServiceTest.php @@ -14,7 +14,7 @@ class SemesterRangeServiceTest extends TestCase public function test_get_school_year_range_falls_back_when_config_missing(): void { - $service = new SemesterRangeService(new SemesterConfigService); + $service = new SemesterRangeService(new SemesterConfigService()); [$start, $end] = $service->getSchoolYearRange('2025-2026'); $this->assertSame('2025-09-01', $start); @@ -29,7 +29,7 @@ class SemesterRangeServiceTest extends TestCase ['id' => 3, 'config_key' => 'last_school_day', 'config_value' => '2026-06-01'], ]); - $service = new SemesterRangeService(new SemesterConfigService); + $service = new SemesterRangeService(new SemesterConfigService()); $semester = $service->getSemesterForDate('2025-10-01'); $this->assertSame('Fall', $semester); @@ -37,7 +37,7 @@ class SemesterRangeServiceTest extends TestCase public function test_normalize_semester(): void { - $service = new SemesterRangeService(new SemesterConfigService); + $service = new SemesterRangeService(new SemesterConfigService()); $this->assertSame('Fall', $service->normalizeSemester('fall')); $this->assertSame('Spring', $service->normalizeSemester('SPRING')); diff --git a/tests/Unit/Services/Settings/ConfigurationServiceTest.php b/tests/Unit/Services/Settings/ConfigurationServiceTest.php index 521cbd18..a69db2eb 100644 --- a/tests/Unit/Services/Settings/ConfigurationServiceTest.php +++ b/tests/Unit/Services/Settings/ConfigurationServiceTest.php @@ -12,7 +12,7 @@ class ConfigurationServiceTest extends TestCase public function test_store_creates_config(): void { - $service = new ConfigurationService; + $service = new ConfigurationService(); $config = $service->store([ 'config_key' => 'school_year', 'config_value' => '2025-2026', diff --git a/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarContextServiceTest.php b/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarContextServiceTest.php index 0745351c..b6d21722 100644 --- a/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarContextServiceTest.php +++ b/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarContextServiceTest.php @@ -9,7 +9,7 @@ class SchoolCalendarContextServiceTest extends TestCase { public function test_event_types_returns_list(): void { - $service = new SchoolCalendarContextService; + $service = new SchoolCalendarContextService(); $types = $service->eventTypes(); $this->assertNotEmpty($types); diff --git a/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarFormatterServiceTest.php b/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarFormatterServiceTest.php index 3d6ded5e..9a07b15a 100644 --- a/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarFormatterServiceTest.php +++ b/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarFormatterServiceTest.php @@ -9,7 +9,7 @@ class SchoolCalendarFormatterServiceTest extends TestCase { public function test_format_event_sets_background_for_no_school(): void { - $service = new SchoolCalendarFormatterService; + $service = new SchoolCalendarFormatterService(); $formatted = $service->formatEvent([ 'id' => 1, 'title' => 'No School Day', @@ -27,7 +27,7 @@ class SchoolCalendarFormatterServiceTest extends TestCase public function test_format_event_normalizes_iso_dates_to_plain_calendar_date(): void { - $service = new SchoolCalendarFormatterService; + $service = new SchoolCalendarFormatterService(); $formatted = $service->formatEvent([ 'id' => 2, 'title' => 'First Day of School', diff --git a/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarMeetingServiceTest.php b/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarMeetingServiceTest.php index 60ed77d3..ddcde851 100644 --- a/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarMeetingServiceTest.php +++ b/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarMeetingServiceTest.php @@ -48,7 +48,7 @@ class SchoolCalendarMeetingServiceTest extends TestCase ], ]); - $service = new SchoolCalendarMeetingService; + $service = new SchoolCalendarMeetingService(); $rows = $service->listMeetings('2025-2026', 'parent', 10); $this->assertCount(1, $rows); diff --git a/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarMutationServiceTest.php b/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarMutationServiceTest.php index e9281d32..de7d2afa 100644 --- a/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarMutationServiceTest.php +++ b/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarMutationServiceTest.php @@ -16,7 +16,7 @@ class SchoolCalendarMutationServiceTest extends TestCase public function test_create_persists_event(): void { - $context = new SchoolCalendarContextService; + $context = new SchoolCalendarContextService(); $notifier = Mockery::mock(SchoolCalendarNotificationService::class); $notifier->shouldReceive('notify')->andReturn([]); @@ -47,7 +47,7 @@ class SchoolCalendarMutationServiceTest extends TestCase 'notification_sent' => 0, ]); - $context = new SchoolCalendarContextService; + $context = new SchoolCalendarContextService(); $notifier = Mockery::mock(SchoolCalendarNotificationService::class); $notifier->shouldReceive('notify')->andReturn([]); diff --git a/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarQueryServiceTest.php b/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarQueryServiceTest.php index 246c3d06..5510dd39 100644 --- a/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarQueryServiceTest.php +++ b/tests/Unit/Services/Settings/SchoolCalendar/SchoolCalendarQueryServiceTest.php @@ -44,7 +44,7 @@ class SchoolCalendarQueryServiceTest extends TestCase ], ]); - $service = new SchoolCalendarQueryService; + $service = new SchoolCalendarQueryService(); $events = $service->listEvents(['school_year' => '2025-2026']); $this->assertCount(1, $events); @@ -84,7 +84,7 @@ class SchoolCalendarQueryServiceTest extends TestCase ], ]); - $service = new SchoolCalendarQueryService; + $service = new SchoolCalendarQueryService(); $events = $service->listEvents(['school_year' => '2025-2026']); $filtered = $service->filterEventsForAudience($events, 'parent'); diff --git a/tests/Unit/Services/Settings/SettingsServiceTest.php b/tests/Unit/Services/Settings/SettingsServiceTest.php index d101ba51..70d4c26d 100644 --- a/tests/Unit/Services/Settings/SettingsServiceTest.php +++ b/tests/Unit/Services/Settings/SettingsServiceTest.php @@ -2,8 +2,10 @@ namespace Tests\Unit\Services\Settings; +use App\Models\Setting; use App\Services\Settings\SettingsService; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Facades\DB; use Tests\TestCase; class SettingsServiceTest extends TestCase @@ -12,7 +14,7 @@ class SettingsServiceTest extends TestCase public function test_update_persists_settings(): void { - $service = new SettingsService; + $service = new SettingsService(); $result = $service->update([ 'site_name' => 'Alrahma', diff --git a/tests/Unit/Services/Staff/StaffCommandServiceTest.php b/tests/Unit/Services/Staff/StaffCommandServiceTest.php index 523c1993..a2c23b2d 100644 --- a/tests/Unit/Services/Staff/StaffCommandServiceTest.php +++ b/tests/Unit/Services/Staff/StaffCommandServiceTest.php @@ -15,7 +15,7 @@ class StaffCommandServiceTest extends TestCase public function test_create_requires_user(): void { - $service = new StaffCommandService(new GlobalConfigService); + $service = new StaffCommandService(new GlobalConfigService()); $this->expectException(\RuntimeException::class); $service->create([ @@ -44,7 +44,7 @@ class StaffCommandServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new StaffCommandService(new GlobalConfigService); + $service = new StaffCommandService(new GlobalConfigService()); $staff = $service->create([ 'user_id' => $user->id, 'firstname' => 'Staff', diff --git a/tests/Unit/Services/Staff/StaffQueryServiceTest.php b/tests/Unit/Services/Staff/StaffQueryServiceTest.php index 9e5fe4f6..75626690 100644 --- a/tests/Unit/Services/Staff/StaffQueryServiceTest.php +++ b/tests/Unit/Services/Staff/StaffQueryServiceTest.php @@ -41,7 +41,7 @@ class StaffQueryServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new StaffQueryService(new GlobalConfigService); + $service = new StaffQueryService(new GlobalConfigService()); $result = $service->paginate([], 1, 10); $this->assertSame(1, $result['paginator']->total()); diff --git a/tests/Unit/Services/Students/StudentAssignmentServiceTest.php b/tests/Unit/Services/Students/StudentAssignmentServiceTest.php index c7b4010c..a0cb4dcc 100644 --- a/tests/Unit/Services/Students/StudentAssignmentServiceTest.php +++ b/tests/Unit/Services/Students/StudentAssignmentServiceTest.php @@ -18,7 +18,7 @@ class StudentAssignmentServiceTest extends TestCase $studentId = $this->seedStudent(); $classSectionId = $this->seedClassSection(); - $service = new StudentAssignmentService(new StudentConfigService); + $service = new StudentAssignmentService(new StudentConfigService()); $result = $service->assignClasses($studentId, [$classSectionId], false); $this->assertTrue($result['ok']); @@ -44,7 +44,7 @@ class StudentAssignmentServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new StudentAssignmentService(new StudentConfigService); + $service = new StudentAssignmentService(new StudentConfigService()); $result = $service->removeClass($studentId, $classSectionId); $this->assertTrue($result['ok']); diff --git a/tests/Unit/Services/Students/StudentProfileServiceTest.php b/tests/Unit/Services/Students/StudentProfileServiceTest.php index fb6d11b1..aabe1091 100644 --- a/tests/Unit/Services/Students/StudentProfileServiceTest.php +++ b/tests/Unit/Services/Students/StudentProfileServiceTest.php @@ -15,7 +15,7 @@ class StudentProfileServiceTest extends TestCase { $studentId = $this->seedStudent(); - $service = new StudentProfileService; + $service = new StudentProfileService(); $result = $service->updateStudent($studentId, [ 'firstname' => 'Lee', 'lastname' => 'Student', diff --git a/tests/Unit/Services/Students/StudentScoreCardServiceTest.php b/tests/Unit/Services/Students/StudentScoreCardServiceTest.php index 2e71ca52..5dd26889 100644 --- a/tests/Unit/Services/Students/StudentScoreCardServiceTest.php +++ b/tests/Unit/Services/Students/StudentScoreCardServiceTest.php @@ -33,7 +33,7 @@ class StudentScoreCardServiceTest extends TestCase 'created_at' => now(), ]); - $service = new StudentScoreCardService; + $service = new StudentScoreCardService(); $result = $service->scoreCard($studentId); $this->assertTrue($result['ok']); diff --git a/tests/Unit/Services/Subjects/SubjectCurriculumServiceTest.php b/tests/Unit/Services/Subjects/SubjectCurriculumServiceTest.php index f5c21017..239a6dcc 100644 --- a/tests/Unit/Services/Subjects/SubjectCurriculumServiceTest.php +++ b/tests/Unit/Services/Subjects/SubjectCurriculumServiceTest.php @@ -14,7 +14,7 @@ class SubjectCurriculumServiceTest extends TestCase public function test_store_creates_entry(): void { $classId = $this->seedClass(); - $service = new SubjectCurriculumService; + $service = new SubjectCurriculumService(); $entry = $service->store([ 'class_id' => $classId, @@ -44,7 +44,7 @@ class SubjectCurriculumServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new SubjectCurriculumService; + $service = new SubjectCurriculumService(); $entry = $service->update($entryId, [ 'class_id' => $classId, 'subject' => 'quran', diff --git a/tests/Unit/Services/Support/SupportRequestServiceTest.php b/tests/Unit/Services/Support/SupportRequestServiceTest.php index 20122dd8..087cab13 100644 --- a/tests/Unit/Services/Support/SupportRequestServiceTest.php +++ b/tests/Unit/Services/Support/SupportRequestServiceTest.php @@ -40,7 +40,7 @@ class SupportRequestServiceTest extends TestCase $mailer = $this->createMock(EmailDispatchService::class); $mailer->method('send')->willReturn(false); - $service = new SupportRequestService(new GlobalConfigService, $mailer); + $service = new SupportRequestService(new GlobalConfigService(), $mailer); $result = $service->create($user->id, [ 'subject' => 'Help', 'message' => 'Need assistance', diff --git a/tests/Unit/Services/System/CleanupSchedulerServiceTest.php b/tests/Unit/Services/System/CleanupSchedulerServiceTest.php index caff5e84..3ee4a583 100644 --- a/tests/Unit/Services/System/CleanupSchedulerServiceTest.php +++ b/tests/Unit/Services/System/CleanupSchedulerServiceTest.php @@ -13,13 +13,13 @@ class CleanupSchedulerServiceTest extends TestCase { Cache::forget('last_cleanup_run'); - $service = new CleanupSchedulerService; + $service = new CleanupSchedulerService(); $this->assertTrue($service->shouldRun('last_cleanup_run', 2)); } public function test_mark_run_sets_cache(): void { - $service = new CleanupSchedulerService; + $service = new CleanupSchedulerService(); $service->markRun('last_cleanup_run'); $this->assertNotNull(Cache::get('last_cleanup_run')); @@ -29,7 +29,7 @@ class CleanupSchedulerServiceTest extends TestCase { Artisan::shouldReceive('call')->once()->with('users:delete-unverified'); - $service = new CleanupSchedulerService; + $service = new CleanupSchedulerService(); $service->runUnverifiedCleanup(); } } diff --git a/tests/Unit/Services/System/ConfigUpdateServiceTest.php b/tests/Unit/Services/System/ConfigUpdateServiceTest.php index 0e025ffe..04c7ddef 100644 --- a/tests/Unit/Services/System/ConfigUpdateServiceTest.php +++ b/tests/Unit/Services/System/ConfigUpdateServiceTest.php @@ -13,7 +13,7 @@ class ConfigUpdateServiceTest extends TestCase public function test_run_task_rejects_unknown_task(): void { - $service = new ConfigUpdateService; + $service = new ConfigUpdateService(); $result = $service->runTask('unknown', false, false, new DateTimeZone('UTC')); $this->assertFalse($result['ok']); @@ -21,7 +21,7 @@ class ConfigUpdateServiceTest extends TestCase public function test_run_task_sets_config_when_forced(): void { - $service = new ConfigUpdateService; + $service = new ConfigUpdateService(); $result = $service->runTask('enable_attendance_on', false, true, new DateTimeZone('UTC')); $this->assertTrue($result['ok']); diff --git a/tests/Unit/Services/System/GlobalConfigServiceTest.php b/tests/Unit/Services/System/GlobalConfigServiceTest.php index 158a00b9..f9895332 100644 --- a/tests/Unit/Services/System/GlobalConfigServiceTest.php +++ b/tests/Unit/Services/System/GlobalConfigServiceTest.php @@ -18,7 +18,7 @@ class GlobalConfigServiceTest extends TestCase ['config_key' => 'school_year', 'config_value' => '2024-2025'], ]); - $service = new GlobalConfigService; + $service = new GlobalConfigService(); $this->assertSame('Fall', $service->getSemester()); $this->assertSame('2024-2025', $service->getSchoolYear()); diff --git a/tests/Unit/Services/System/TimeServiceTest.php b/tests/Unit/Services/System/TimeServiceTest.php index c06529a4..00c24b1c 100644 --- a/tests/Unit/Services/System/TimeServiceTest.php +++ b/tests/Unit/Services/System/TimeServiceTest.php @@ -9,7 +9,7 @@ class TimeServiceTest extends TestCase { public function test_to_utc_and_to_local_round_trip(): void { - $service = new TimeService; + $service = new TimeService(); $utc = $service->toUtc('2025-01-01 12:00:00', 'America/New_York'); $local = $service->toLocal($utc, 'UTC', 'America/New_York'); diff --git a/tests/Unit/Services/Teachers/TeacherAbsenceServiceTest.php b/tests/Unit/Services/Teachers/TeacherAbsenceServiceTest.php index b03e6f63..c626aea5 100644 --- a/tests/Unit/Services/Teachers/TeacherAbsenceServiceTest.php +++ b/tests/Unit/Services/Teachers/TeacherAbsenceServiceTest.php @@ -2,9 +2,9 @@ namespace Tests\Unit\Services\Teachers; +use App\Services\Staff\StaffTimeOffLinkService; use App\Services\SemesterRangeService; use App\Services\Semesters\SemesterConfigService; -use App\Services\Staff\StaffTimeOffLinkService; use App\Services\Teachers\TeacherAbsenceService; use App\Services\Teachers\TeacherConfigService; use Carbon\Carbon; @@ -23,9 +23,9 @@ class TeacherAbsenceServiceTest extends TestCase $teacherId = $this->seedTeacherUser(); $service = new TeacherAbsenceService( - new TeacherConfigService, - new SemesterRangeService(new SemesterConfigService), - new StaffTimeOffLinkService + new TeacherConfigService(), + new SemesterRangeService(new SemesterConfigService()), + new StaffTimeOffLinkService() ); $data = $service->formData($teacherId); @@ -42,9 +42,9 @@ class TeacherAbsenceServiceTest extends TestCase $teacherId = $this->seedTeacherUser(); $service = new TeacherAbsenceService( - new TeacherConfigService, - new SemesterRangeService(new SemesterConfigService), - new StaffTimeOffLinkService + new TeacherConfigService(), + new SemesterRangeService(new SemesterConfigService()), + new StaffTimeOffLinkService() ); $date = $service->formData($teacherId)['available_dates'][0]; diff --git a/tests/Unit/Services/Teachers/TeacherAssignmentServiceTest.php b/tests/Unit/Services/Teachers/TeacherAssignmentServiceTest.php index aadd15d7..73344c38 100644 --- a/tests/Unit/Services/Teachers/TeacherAssignmentServiceTest.php +++ b/tests/Unit/Services/Teachers/TeacherAssignmentServiceTest.php @@ -18,7 +18,7 @@ class TeacherAssignmentServiceTest extends TestCase $teacherId = $this->seedTeacherUser(); $classSectionId = $this->seedClassSection(); - $service = new TeacherAssignmentService(new TeacherConfigService); + $service = new TeacherAssignmentService(new TeacherConfigService()); $result = $service->assign([ 'teacher_id' => $teacherId, 'class_section_id' => $classSectionId, @@ -51,7 +51,7 @@ class TeacherAssignmentServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new TeacherAssignmentService(new TeacherConfigService); + $service = new TeacherAssignmentService(new TeacherConfigService()); $result = $service->delete([ 'teacher_id' => $teacherId, 'class_section_id' => $classSectionId, diff --git a/tests/Unit/Services/Teachers/TeacherDashboardServiceTest.php b/tests/Unit/Services/Teachers/TeacherDashboardServiceTest.php index cb210b59..f8880cb2 100644 --- a/tests/Unit/Services/Teachers/TeacherDashboardServiceTest.php +++ b/tests/Unit/Services/Teachers/TeacherDashboardServiceTest.php @@ -20,7 +20,7 @@ class TeacherDashboardServiceTest extends TestCase $this->seedTeacherAssignment($teacherId, $classSectionId); $this->seedStudent($teacherId, $classSectionId); - $service = new TeacherDashboardService(new TeacherConfigService); + $service = new TeacherDashboardService(new TeacherConfigService()); $data = $service->classView($teacherId, $classSectionId); $this->assertSame($classSectionId, $data['active_class_section_id']); diff --git a/tests/Unit/Services/Ui/UiStyleServiceTest.php b/tests/Unit/Services/Ui/UiStyleServiceTest.php index 44d11bf9..0cea331a 100644 --- a/tests/Unit/Services/Ui/UiStyleServiceTest.php +++ b/tests/Unit/Services/Ui/UiStyleServiceTest.php @@ -29,7 +29,7 @@ class UiStyleServiceTest extends TestCase 'school_year' => '2025-2026', ]); - $service = new UiStyleService; + $service = new UiStyleService(); $prefs = $service->update($user->id, [ 'accent' => 'blue', 'menu' => 'custom', diff --git a/tests/Unit/Services/Users/InactiveUserCleanupServiceTest.php b/tests/Unit/Services/Users/InactiveUserCleanupServiceTest.php index 2b09001a..82fd3d16 100644 --- a/tests/Unit/Services/Users/InactiveUserCleanupServiceTest.php +++ b/tests/Unit/Services/Users/InactiveUserCleanupServiceTest.php @@ -40,7 +40,7 @@ class InactiveUserCleanupServiceTest extends TestCase 'role_id' => 1, ]); - $service = new InactiveUserCleanupService; + $service = new InactiveUserCleanupService(); $result = $service->cleanup(15); $this->assertSame(1, $result['deleted_users']); diff --git a/tests/Unit/Services/Users/UserListServiceTest.php b/tests/Unit/Services/Users/UserListServiceTest.php index 1efd9208..565d7a42 100644 --- a/tests/Unit/Services/Users/UserListServiceTest.php +++ b/tests/Unit/Services/Users/UserListServiceTest.php @@ -2,6 +2,7 @@ namespace Tests\Unit\Services\Users; +use App\Models\User; use App\Services\Users\UserListService; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; diff --git a/tests/Unit/Services/Whatsapp/WhatsappContactServiceTest.php b/tests/Unit/Services/Whatsapp/WhatsappContactServiceTest.php index 8cdabaf6..77152bf1 100644 --- a/tests/Unit/Services/Whatsapp/WhatsappContactServiceTest.php +++ b/tests/Unit/Services/Whatsapp/WhatsappContactServiceTest.php @@ -47,7 +47,7 @@ class WhatsappContactServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new WhatsappContactService(new WhatsappContextService); + $service = new WhatsappContactService(new WhatsappContextService()); $contacts = $service->listParentContacts('2025-2026', 'Fall'); $this->assertCount(2, $contacts); diff --git a/tests/Unit/Services/Whatsapp/WhatsappContextServiceTest.php b/tests/Unit/Services/Whatsapp/WhatsappContextServiceTest.php index 1d05393e..f4b7c0d5 100644 --- a/tests/Unit/Services/Whatsapp/WhatsappContextServiceTest.php +++ b/tests/Unit/Services/Whatsapp/WhatsappContextServiceTest.php @@ -13,7 +13,7 @@ class WhatsappContextServiceTest extends TestCase public function test_school_year_aliases_generate_expected_values(): void { - $service = new WhatsappContextService; + $service = new WhatsappContextService(); [$aliases, $canonical, $startYear] = $service->schoolYearAliases('2025/2026'); $this->assertContains('2025-2026', $aliases); @@ -33,7 +33,7 @@ class WhatsappContextServiceTest extends TestCase 'updated_at' => now(), ]); - $service = new WhatsappContextService; + $service = new WhatsappContextService(); $this->assertTrue($service->hasRosterForYear('2025-2026')); $this->assertFalse($service->hasRosterForYear('2030-2031')); diff --git a/tests/Unit/Services/Whatsapp/WhatsappInviteBundleServiceTest.php b/tests/Unit/Services/Whatsapp/WhatsappInviteBundleServiceTest.php index a8f399a6..903f151c 100644 --- a/tests/Unit/Services/Whatsapp/WhatsappInviteBundleServiceTest.php +++ b/tests/Unit/Services/Whatsapp/WhatsappInviteBundleServiceTest.php @@ -77,7 +77,7 @@ class WhatsappInviteBundleServiceTest extends TestCase ], ]; - $service = new WhatsappInviteBundleService; + $service = new WhatsappInviteBundleService(); $bundle = $service->bundleForParent(10, $linkBySection, '2025-2026', 'Fall'); $this->assertNotNull($bundle); @@ -87,7 +87,7 @@ class WhatsappInviteBundleServiceTest extends TestCase public function test_consolidate_bundles_merges_by_parent(): void { - $service = new WhatsappInviteBundleService; + $service = new WhatsappInviteBundleService(); $merged = $service->consolidateBundles([ [ diff --git a/tests/Unit/Services/Whatsapp/WhatsappInviteNotificationServiceTest.php b/tests/Unit/Services/Whatsapp/WhatsappInviteNotificationServiceTest.php index f486bc75..83eb0deb 100644 --- a/tests/Unit/Services/Whatsapp/WhatsappInviteNotificationServiceTest.php +++ b/tests/Unit/Services/Whatsapp/WhatsappInviteNotificationServiceTest.php @@ -14,7 +14,7 @@ class WhatsappInviteNotificationServiceTest extends TestCase public function test_dispatch_returns_error_when_no_listeners(): void { - $service = new WhatsappInviteNotificationService; + $service = new WhatsappInviteNotificationService(); $result = $service->dispatch([], '2025-2026', 'Fall'); $this->assertFalse($result['ok']); @@ -22,9 +22,10 @@ class WhatsappInviteNotificationServiceTest extends TestCase public function test_dispatch_triggers_event_when_listener_registered(): void { - Event::listen(WhatsappInvitesSend::class, static function () {}); + Event::listen(WhatsappInvitesSend::class, static function () { + }); - $service = new WhatsappInviteNotificationService; + $service = new WhatsappInviteNotificationService(); $result = $service->dispatch([[ 'parent' => ['id' => 10], 'emails' => ['parent1@example.com'], diff --git a/tests/Unit/Services/Whatsapp/WhatsappInviteServiceTest.php b/tests/Unit/Services/Whatsapp/WhatsappInviteServiceTest.php index b942eb0c..375a7a8e 100644 --- a/tests/Unit/Services/Whatsapp/WhatsappInviteServiceTest.php +++ b/tests/Unit/Services/Whatsapp/WhatsappInviteServiceTest.php @@ -19,12 +19,13 @@ class WhatsappInviteServiceTest extends TestCase public function test_send_returns_success_for_parent_mode(): void { $this->seedInviteData(); - Event::listen(WhatsappInvitesSend::class, static function () {}); + Event::listen(WhatsappInvitesSend::class, static function () { + }); $service = new WhatsappInviteService( - new WhatsappContextService, - new WhatsappInviteBundleService, - new WhatsappInviteNotificationService + new WhatsappContextService(), + new WhatsappInviteBundleService(), + new WhatsappInviteNotificationService() ); $result = $service->send([ diff --git a/tests/Unit/Services/Whatsapp/WhatsappLinkServiceTest.php b/tests/Unit/Services/Whatsapp/WhatsappLinkServiceTest.php index 8d0377b7..1ae3e506 100644 --- a/tests/Unit/Services/Whatsapp/WhatsappLinkServiceTest.php +++ b/tests/Unit/Services/Whatsapp/WhatsappLinkServiceTest.php @@ -14,7 +14,7 @@ class WhatsappLinkServiceTest extends TestCase public function test_upsert_creates_link(): void { - $service = new WhatsappLinkService(new WhatsappContextService); + $service = new WhatsappLinkService(new WhatsappContextService()); $link = $service->upsert([ 'class_section_id' => 300, @@ -57,7 +57,7 @@ class WhatsappLinkServiceTest extends TestCase ], ]); - $service = new WhatsappLinkService(new WhatsappContextService); + $service = new WhatsappLinkService(new WhatsappContextService()); $page = $service->paginate(['active' => true]); $this->assertCount(1, $page->items()); diff --git a/tests/Unit/Services/Whatsapp/WhatsappMembershipServiceTest.php b/tests/Unit/Services/Whatsapp/WhatsappMembershipServiceTest.php index 5068c1e0..6b122d10 100644 --- a/tests/Unit/Services/Whatsapp/WhatsappMembershipServiceTest.php +++ b/tests/Unit/Services/Whatsapp/WhatsappMembershipServiceTest.php @@ -13,7 +13,7 @@ class WhatsappMembershipServiceTest extends TestCase public function test_update_membership_saves_primary(): void { - $service = new WhatsappMembershipService; + $service = new WhatsappMembershipService(); $result = $service->updateMembership([ 'class_section_id' => 200, @@ -36,7 +36,7 @@ class WhatsappMembershipServiceTest extends TestCase { Schema::shouldReceive('hasTable')->with('whatsapp_group_memberships')->andReturn(false); - $service = new WhatsappMembershipService; + $service = new WhatsappMembershipService(); $result = $service->updateMembership([ 'class_section_id' => 200, 'primary_id' => 10,