diff --git a/app/Filament/Pages/ReportPreview.php b/app/Filament/Pages/ReportPreview.php index 2e80025..fb33b43 100644 --- a/app/Filament/Pages/ReportPreview.php +++ b/app/Filament/Pages/ReportPreview.php @@ -8,6 +8,7 @@ use App\Models\ClassRoom; use App\Models\ClassSubject; use App\Models\CompetencyAchievement; use App\Models\ExtracurricularAssessment; +use App\Models\HomeRoomTeacher; use App\Models\Student; use App\Models\SchoolInformation; use App\Models\Subject; @@ -17,6 +18,7 @@ use Filament\Pages\Page; use Carbon\Carbon; use function PHPUnit\Framework\isEmpty; use function Symfony\Component\String\s; +use Barryvdh\DomPDF\Facade\Pdf; Carbon::setLocale('id'); @@ -40,6 +42,8 @@ class ReportPreview extends Page public $izin = 0; public $tanpa_keterangan = 0; + public $home_room_teacher; + public function mount() { $this->loadData(); @@ -55,11 +59,10 @@ class ReportPreview extends Page 'tanpa_keterangan' => 'required|integer|min:0', ]); - $this->dispatch('notify', [ - 'title' => 'Berhasil', - 'message' => 'Data ketidakhadiran diperbarui', - 'type' => 'success' - ]); + Notification::make() + ->title('Data Kehadiran Disimpan') + ->success() + ->send(); } protected function loadData() : void @@ -161,15 +164,14 @@ class ReportPreview extends Page ->toArray(); $this->table["extracurricular"] = $extracurricular; - } - public function downloadPdf() - { - $view = $this->render()->render(); - $pdf = PDF::loadHTML($view)->setPaper('a4', 'landscape'); - return response()->streamDownload(function () use ($pdf) { - echo $pdf->stream(); - }, $this->student->full_name . '.pdf'); + $homeRoom = HomeRoomTeacher::with(['teacher']) + ->where('class_room_id', $this->class->id) + ->where('academic_year_id', $this->academic_year->id) + ->firstOrFail() + ->toArray(); + + $this->home_room_teacher = $homeRoom ?? []; } public function extractClassLetter($className) diff --git a/app/Filament/Pages/SchoolInformation.php b/app/Filament/Pages/SchoolInformation.php index 255081b..d435c34 100644 --- a/app/Filament/Pages/SchoolInformation.php +++ b/app/Filament/Pages/SchoolInformation.php @@ -22,6 +22,16 @@ class SchoolInformation extends Page implements HasForms protected static ?string $navigationGroup = 'Settings'; protected static ?int $navigationSort = 999; // Biar muncul paling bawah + public static function canAccess(): bool + { + return auth()->user()->hasAnyRole(['super_admin']); + } + + public static function shouldRegisterNavigation(): bool + { + return auth()->user()->hasAnyRole(['super_admin']); + } + public ?array $data = []; public ?SchoolInformationModel $record = null; diff --git a/app/Filament/Resources/UserResource.php b/app/Filament/Resources/UserResource.php index 4fdd054..a8b616a 100644 --- a/app/Filament/Resources/UserResource.php +++ b/app/Filament/Resources/UserResource.php @@ -29,21 +29,43 @@ class UserResource extends Resource Forms\Components\TextInput::make('name') ->required() ->maxLength(255), + Forms\Components\TextInput::make('email') ->email() ->required() ->maxLength(255), + Forms\Components\TextInput::make('password') ->password() ->required(fn (string $context): bool => $context === 'create') ->dehydrateStateUsing(fn ($state) => Hash::make($state)) ->dehydrated(fn ($state) => filled($state)) ->maxLength(255), + Forms\Components\Select::make('role') ->relationship('roles', 'name') ->preload() ->searchable() ->required(), + + Forms\Components\TextInput::make('nip') + ->label('NIP') + ->maxLength(255), + + Forms\Components\Select::make('gender') + ->options([ + 'L' => 'L', + 'P' => 'P', + ]), + + Forms\Components\DatePicker::make('birth_date'), + + Forms\Components\TextInput::make('phone') + ->tel() + ->maxLength(255), + + Forms\Components\Textarea::make('address') + ->columnSpanFull(), ]); } @@ -55,6 +77,18 @@ class UserResource extends Resource ->searchable(), Tables\Columns\TextColumn::make('email') ->searchable(), + Tables\Columns\TextColumn::make('nip') + ->label('NIP') + ->searchable(), + Tables\Columns\TextColumn::make('gender') + ->formatStateUsing(fn (string $state): string => ucfirst($state)), + Tables\Columns\TextColumn::make('birth_date') + ->date() + ->sortable(), + Tables\Columns\TextColumn::make('phone') + ->searchable(), + Tables\Columns\TextColumn::make('roles.name') + ->searchable(), Tables\Columns\TextColumn::make('created_at') ->dateTime() ->sortable() @@ -63,7 +97,6 @@ class UserResource extends Resource ->dateTime() ->sortable() ->toggleable(isToggledHiddenByDefault: true), - Tables\Columns\TextColumn::make('roles.name')->searchable(), ]) ->filters([ // diff --git a/app/Http/Controllers/ReportPDFController.php b/app/Http/Controllers/ReportPDFController.php new file mode 100644 index 0000000..dc03bf6 --- /dev/null +++ b/app/Http/Controllers/ReportPDFController.php @@ -0,0 +1,229 @@ +query(); + $defaultParams = ["studentId", "classId", "yearId", "semester", "sakit", "izin", "tanpa_keterangan"]; + + try { + $this->validateParameters($params, $defaultParams); + } catch (\Illuminate\Validation\ValidationException $e) { + Notification::make() + ->title('Parameter tidak valid: ' . $e->getMessage()) + ->danger() + ->send(); + return back(); + } + + + $this->student = Student::findOrFail($params["studentId"]); + $this->class = ClassRoom::findOrFail($params["classId"]); + $this->academic_year = AcademicYear::findOrFail($params["yearId"]); + $this->semester = $params["semester"]; + + $this->school_information = SchoolInformation::firstOrFail(); + + $this->class_name = $this->toRoman($this->class->class_level) . ' ' . $this->extractClassLetter($this->class->class_name); + + $this->loadAssessment(); + + $data = [ + 'student' => $this->student, + 'school_information' => $this->school_information, + 'table' => $this->table, + 'sakit' => $params['sakit'], + 'izin' => $params['izin'], + 'tanpa_keterangan' => $params['tanpa_keterangan'], + 'class_name' => $this->class_name, + 'semester' => $params['semester'], + 'academic_year' => $this->academic_year, + 'home_room_teacher' => $this->home_room_teacher, + ]; + + $pdf = Pdf::loadView('print.report', $data) + ->setPaper('a4', 'portrait') + ->setOption('isRemoteEnabled', true) + ->setOption('isHtml5ParserEnabled', true); + + return response()->streamDownload( + function () use ($pdf) { + echo $pdf->stream(); + }, + 'Rapor_' . $this->student->full_name . '.pdf' + ); + } + + protected function loadAssessment(): void + { + $student_id = $this->student->id; + $class_id = $this->class->id; + $semester = $this->semester; + $year_id = $this->academic_year->id; + + // Assessment Mapping + $assessments = Assessment::where('semester', $this->semester) + ->whereHas('teacherSubject', function($query) use ($class_id, $year_id) { + $query->where('academic_year_id', $year_id) + ->where('class_id', $class_id); + }) + ->where('student_id', $this->student->id) + ->with('teacherSubject.subject', 'student') + ->get() + ->map(function ($as) use ($class_id) { + $subject = $as->teacherSubject->subject ?? null; + + if (!$subject) { + return null; + } + + $competencyAchievements = CompetencyAchievement::where('class_room_id', $class_id) + ->where('subject_id', $subject->id) + ->where('min_score', '<=', $as->score) + ->where('max_score', '>=', $as->score) + ->first(); + + return [ + "score" => $as->score, + "subject" => $subject->name, + "category" => $subject->category, + "competency_achievement" => $competencyAchievements ? $this->student->full_name . ' ' . $competencyAchievements->description : '-', + ]; + }) + ->filter() // Hapus null jika ada + ->sortByDesc('subject') + ->sortBy(function ($item) { + return $item['category'] === 'umum' ? 0 : 1; + }) + ->values() + ->toArray(); + + $this->table["assessments"]['umum'] = array_filter($assessments, function ($item) { + return $item["category"] === "umum"; + }); + + $this->table["assessments"]['muatan lokal'] = array_filter($assessments, function ($item) { + return $item["category"] === "muatan lokal"; + }); + + $this->table["assessments"]['seni'] = array_filter($assessments, function ($item) { + return $item["category"] === "seni"; + }); + + $extracurricular = ExtracurricularAssessment::with('classStudent','extracurricular') + ->where('semester', $this->semester) + ->whereHas('classStudent', function($query) use ($class_id, $year_id) { + $query->where('academic_year_id', $year_id) + ->where('class_room_id', $class_id) + ->where('student_id', $this->student->id); + }) + ->get() + ->map(function ($as) { + return [ + "name" => $as->extracurricular->name, + "predicate" => $as->predicate, + "description" => $as->description, + ]; + }) + ->toArray(); + + $this->table["extracurricular"] = $extracurricular; + + $homeRoom = HomeRoomTeacher::with(['teacher']) + ->where('class_room_id', $this->class->id) + ->where('academic_year_id', $this->academic_year->id) + ->firstOrFail() + ->toArray(); + + $this->home_room_teacher = $homeRoom ?? []; + } + + protected function validateParameters(array $params, array $allowedParams): void + { + $validator = Validator::make($params, [ + 'studentId' => 'required|integer', + 'classId' => 'required|integer', + 'yearId' => 'required|integer', + 'semester' => 'required|in:first,second', + 'sakit' => 'nullable|integer|min:0', + 'izin' => 'nullable|integer|min:0', + 'tanpa_keterangan' => 'nullable|integer|min:0', + ]); + + if ($validator->fails()) { + throw new \Illuminate\Validation\ValidationException($validator); + } + + foreach ($params as $key => $value) { + if (!in_array($key, $allowedParams)) { + throw new \InvalidArgumentException("Parameter {$key} tidak valid"); + } + } + } + + public function extractClassLetter($className): string + { + preg_match('/[A-Z]+$/i', trim($className), $matches); + return $matches[0] ?? ''; + } + + public function toRoman($number): string + { + $map = [ + 'M' => 1000, + 'CM' => 900, + 'D' => 500, + 'CD' => 400, + 'C' => 100, + 'XC' => 90, + 'L' => 50, + 'XL' => 40, + 'X' => 10, + 'IX' => 9, + 'V' => 5, + 'IV' => 4, + 'I' => 1, + ]; + + $returnValue = ''; + while ($number > 0) { + foreach ($map as $roman => $int) { + if ($number >= $int) { + $number -= $int; + $returnValue .= $roman; + break; + } + } + } + + return $returnValue; + } +} diff --git a/app/Policies/AcademicYearPolicy.php b/app/Policies/AcademicYearPolicy.php new file mode 100644 index 0000000..dd35226 --- /dev/null +++ b/app/Policies/AcademicYearPolicy.php @@ -0,0 +1,66 @@ +can('view_any_academic::year'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, AcademicYear $academicYear): bool + { + return $user->can('view_academic::year'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->can('create_academic::year'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, AcademicYear $academicYear): bool + { + return $user->can('update_academic::year'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, AcademicYear $academicYear): bool + { + return $user->can('delete_academic::year'); + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, AcademicYear $academicYear): bool + { + return $user->can('restore_academic::year'); + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, AcademicYear $academicYear): bool + { + return $user->can('force_delete_academic::year'); + } +} diff --git a/app/Policies/ClassStudentPolicy.php b/app/Policies/ClassStudentPolicy.php new file mode 100644 index 0000000..e03ddbb --- /dev/null +++ b/app/Policies/ClassStudentPolicy.php @@ -0,0 +1,66 @@ +can('view_any_class::student'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, ClassStudent $classStudent): bool + { + return $user->can('view_class::student'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->can('create_class::student'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, ClassStudent $classStudent): bool + { + return $user->can('update_class::student'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, ClassStudent $classStudent): bool + { + return $user->can('delete_class::student'); + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, ClassStudent $classStudent): bool + { + return $user->can('restore_class::student'); + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, ClassStudent $classStudent): bool + { + return $user->can('force_delete_class::student'); + } +} diff --git a/app/Policies/ClassSubjectPolicy.php b/app/Policies/ClassSubjectPolicy.php new file mode 100644 index 0000000..40ddf59 --- /dev/null +++ b/app/Policies/ClassSubjectPolicy.php @@ -0,0 +1,66 @@ +can('view_any_class::subject'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, ClassSubject $classSubject): bool + { + return $user->can('view_class::subject'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->can('create_class::subject'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, ClassSubject $classSubject): bool + { + return $user->can('update_class::subject'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, ClassSubject $classSubject): bool + { + return $user->can('delete_class::subject'); + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, ClassSubject $classSubject): bool + { + return $user->can('restore_class::subject'); + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, ClassSubject $classSubject): bool + { + return $user->can('force_delete_class::subject'); + } +} diff --git a/app/Policies/CompetencyAchievementPolicy.php b/app/Policies/CompetencyAchievementPolicy.php new file mode 100644 index 0000000..a1b745f --- /dev/null +++ b/app/Policies/CompetencyAchievementPolicy.php @@ -0,0 +1,66 @@ +can('view_any_competency::achievement'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, CompetencyAchievement $competencyAchievement): bool + { + return $user->can('view_competency::achievement'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->can('create_competency::achievement'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, CompetencyAchievement $competencyAchievement): bool + { + return $user->can('update_competency::achievement'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, CompetencyAchievement $competencyAchievement): bool + { + return $user->can('delete_competency::achievement'); + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, CompetencyAchievement $competencyAchievement): bool + { + return $user->can('restore_competency::achievement'); + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, CompetencyAchievement $competencyAchievement): bool + { + return $user->can('force_delete_competency::achievement'); + } +} diff --git a/app/Policies/ExtracurricularAssessmentPolicy.php b/app/Policies/ExtracurricularAssessmentPolicy.php new file mode 100644 index 0000000..0a2adc6 --- /dev/null +++ b/app/Policies/ExtracurricularAssessmentPolicy.php @@ -0,0 +1,66 @@ +can('view_any_extracurricular::assessment'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, ExtracurricularAssessment $extracurricularAssessment): bool + { + return $user->can('view_extracurricular::assessment'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->can('create_extracurricular::assessment'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, ExtracurricularAssessment $extracurricularAssessment): bool + { + return $user->can('update_extracurricular::assessment'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, ExtracurricularAssessment $extracurricularAssessment): bool + { + return $user->can('delete_extracurricular::assessment'); + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, ExtracurricularAssessment $extracurricularAssessment): bool + { + return $user->can('restore_extracurricular::assessment'); + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, ExtracurricularAssessment $extracurricularAssessment): bool + { + return $user->can('force_delete_extracurricular::assessment'); + } +} diff --git a/app/Policies/HomeRoomTeacherPolicy.php b/app/Policies/HomeRoomTeacherPolicy.php new file mode 100644 index 0000000..43b22be --- /dev/null +++ b/app/Policies/HomeRoomTeacherPolicy.php @@ -0,0 +1,66 @@ +can('view_any_home::rome::teacher'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, HomeRoomTeacher $homeRomeTeacher): bool + { + return $user->can('view_home::rome::teacher'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->can('create_home::rome::teacher'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, HomeRoomTeacher $homeRomeTeacher): bool + { + return $user->can('update_home::rome::teacher'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, HomeRoomTeacher $homeRomeTeacher): bool + { + return $user->can('delete_home::rome::teacher'); + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, HomeRoomTeacher $homeRomeTeacher): bool + { + return $user->can('restore_home::rome::teacher'); + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, HomeRoomTeacher $homeRomeTeacher): bool + { + return $user->can('force_delete_home::rome::teacher'); + } +} diff --git a/app/Policies/SchoolInformationPolicy.php b/app/Policies/SchoolInformationPolicy.php new file mode 100644 index 0000000..61908b1 --- /dev/null +++ b/app/Policies/SchoolInformationPolicy.php @@ -0,0 +1,66 @@ +can('view_any_school::information'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, SchoolInformation $schoolInformation): bool + { + return $user->can('view_school::information'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->can('create_school::information'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, SchoolInformation $schoolInformation): bool + { + return $user->can('update_school::information'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, SchoolInformation $schoolInformation): bool + { + return $user->can('delete_school::information'); + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, SchoolInformation $schoolInformation): bool + { + return $user->can('restore_school::information'); + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, SchoolInformation $schoolInformation): bool + { + return $user->can('force_delete_school::information'); + } +} diff --git a/app/Policies/SubjectScopePolicy.php b/app/Policies/SubjectScopePolicy.php deleted file mode 100644 index 1a95c02..0000000 --- a/app/Policies/SubjectScopePolicy.php +++ /dev/null @@ -1,65 +0,0 @@ -can('view_any_subject::scope'); - } - - /** - * Determine whether the user can view the model. - */ - public function view(User $user, SubjectScope $subjectScope): bool - { - return $user->can('view_subject::scope'); - } - - /** - * Determine whether the user can create models. - */ - public function create(User $user): bool - { - return $user->can('create_subject::scope'); - } - - /** - * Determine whether the user can update the model. - */ - public function update(User $user, SubjectScope $subjectScope): bool - { - return $user->can('update_subject::scope'); - } - - /** - * Determine whether the user can delete the model. - */ - public function delete(User $user, SubjectScope $subjectScope): bool - { - return $user->can('delete_subject::scope'); - } - - /** - * Determine whether the user can restore the model. - */ - public function restore(User $user, SubjectScope $subjectScope): bool - { - return $user->can('restore_subject::scope'); - } - - /** - * Determine whether the user can permanently delete the model. - */ - public function forceDelete(User $user, SubjectScope $subjectScope): bool - { - return $user->can('force_delete_subject::scope'); - } -} diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index d4de171..a016cfb 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -56,6 +56,7 @@ class AdminPanelProvider extends PanelProvider ]) ->plugins([ \BezhanSalleh\FilamentShield\FilamentShieldPlugin::make(), - ]); + ]) + ->brandName('Sistem Akademik Sekolah'); } } diff --git a/composer.json b/composer.json index b514135..cd46669 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "license": "MIT", "require": { "php": "^8.2", + "barryvdh/laravel-dompdf": "^3.1", "bezhansalleh/filament-shield": "^3.3", "laravel/framework": "^11.31", "laravel/tinker": "^2.9" diff --git a/composer.lock b/composer.lock index d01eb91..0cbd356 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6ab55b3e872edca1f0857b78d520564b", + "content-hash": "c3a721ae1c529499b996247d90300571", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -72,6 +72,83 @@ }, "time": "2025-04-06T06:54:34+00:00" }, + { + "name": "barryvdh/laravel-dompdf", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-dompdf.git", + "reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d", + "reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d", + "shasum": "" + }, + "require": { + "dompdf/dompdf": "^3.0", + "illuminate/support": "^9|^10|^11|^12", + "php": "^8.1" + }, + "require-dev": { + "larastan/larastan": "^2.7|^3.0", + "orchestra/testbench": "^7|^8|^9|^10", + "phpro/grumphp": "^2.5", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "PDF": "Barryvdh\\DomPDF\\Facade\\Pdf", + "Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf" + }, + "providers": [ + "Barryvdh\\DomPDF\\ServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\DomPDF\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "A DOMPDF Wrapper for Laravel", + "keywords": [ + "dompdf", + "laravel", + "pdf" + ], + "support": { + "issues": "https://github.com/barryvdh/laravel-dompdf/issues", + "source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.1" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2025-02-13T15:07:54+00:00" + }, { "name": "bezhansalleh/filament-shield", "version": "3.3.5", @@ -940,6 +1017,161 @@ ], "time": "2024-02-05T11:56:58+00:00" }, + { + "name": "dompdf/dompdf", + "version": "v3.1.0", + "source": { + "type": "git", + "url": "https://github.com/dompdf/dompdf.git", + "reference": "a51bd7a063a65499446919286fb18b518177155a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/a51bd7a063a65499446919286fb18b518177155a", + "reference": "a51bd7a063a65499446919286fb18b518177155a", + "shasum": "" + }, + "require": { + "dompdf/php-font-lib": "^1.0.0", + "dompdf/php-svg-lib": "^1.0.0", + "ext-dom": "*", + "ext-mbstring": "*", + "masterminds/html5": "^2.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "ext-gd": "*", + "ext-json": "*", + "ext-zip": "*", + "mockery/mockery": "^1.3", + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0" + }, + "suggest": { + "ext-gd": "Needed to process images", + "ext-gmagick": "Improves image processing performance", + "ext-imagick": "Improves image processing performance", + "ext-zlib": "Needed for pdf stream compression" + }, + "type": "library", + "autoload": { + "psr-4": { + "Dompdf\\": "src/" + }, + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "The Dompdf Community", + "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" + } + ], + "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", + "homepage": "https://github.com/dompdf/dompdf", + "support": { + "issues": "https://github.com/dompdf/dompdf/issues", + "source": "https://github.com/dompdf/dompdf/tree/v3.1.0" + }, + "time": "2025-01-15T14:09:04+00:00" + }, + { + "name": "dompdf/php-font-lib", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-font-lib.git", + "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", + "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "FontLib\\": "src/FontLib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "The FontLib Community", + "homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse, export and make subsets of different types of font files.", + "homepage": "https://github.com/dompdf/php-font-lib", + "support": { + "issues": "https://github.com/dompdf/php-font-lib/issues", + "source": "https://github.com/dompdf/php-font-lib/tree/1.0.1" + }, + "time": "2024-12-02T14:37:59+00:00" + }, + { + "name": "dompdf/php-svg-lib", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-svg-lib.git", + "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af", + "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0", + "sabberworm/php-css-parser": "^8.4" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Svg\\": "src/Svg" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "The SvgLib Community", + "homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse and export to PDF SVG files.", + "homepage": "https://github.com/dompdf/php-svg-lib", + "support": { + "issues": "https://github.com/dompdf/php-svg-lib/issues", + "source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0" + }, + "time": "2024-04-29T13:26:35+00:00" + }, { "name": "dragonmantank/cron-expression", "version": "v3.4.0", @@ -4797,6 +5029,71 @@ ], "time": "2025-02-25T09:09:36+00:00" }, + { + "name": "sabberworm/php-css-parser", + "version": "v8.8.0", + "source": { + "type": "git", + "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", + "reference": "3de493bdddfd1f051249af725c7e0d2c38fed740" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/3de493bdddfd1f051249af725c7e0d2c38fed740", + "reference": "3de493bdddfd1f051249af725c7e0d2c38fed740", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + }, + "require-dev": { + "phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41" + }, + "suggest": { + "ext-mbstring": "for parsing UTF-8 CSS" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Sabberworm\\CSS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Raphael Schweikert" + }, + { + "name": "Oliver Klee", + "email": "github@oliverklee.de" + }, + { + "name": "Jake Hotson", + "email": "jake.github@qzdesign.co.uk" + } + ], + "description": "Parser for CSS Files written in PHP", + "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", + "keywords": [ + "css", + "parser", + "stylesheet" + ], + "support": { + "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.8.0" + }, + "time": "2025-03-23T17:59:05+00:00" + }, { "name": "spatie/color", "version": "1.8.0", diff --git a/resources/views/filament/pages/report-preview.blade.php b/resources/views/filament/pages/report-preview.blade.php index 87c636d..f31cfd6 100644 --- a/resources/views/filament/pages/report-preview.blade.php +++ b/resources/views/filament/pages/report-preview.blade.php @@ -173,8 +173,8 @@ Depok, {{ \Carbon\Carbon::now()->translatedFormat('d F Y') }}
Wali Kelas {{ $this->class_name ?? "-" }}


- Siti Mawarni, S.Pd
- NIP. 197502021990121001 + {{ $home_room_teacher["teacher"]["name"] ?? '-' }}
+ NIP. {{ $home_room_teacher["teacher"]["nip"] ?? '-' }} @@ -223,9 +223,19 @@ - Generate Report + tag="a" + href="{{ route('report.pdf', [ + 'studentId' => $this->student->id, + 'classId' => $this->class->id, + 'yearId' => $this->academic_year->id, + 'semester' => $this->semester, + 'sakit' => $this->sakit, + 'izin' => $this->izin, + 'tanpa_keterangan' => $this->tanpa_keterangan, + ]) }}" + target="_blank" + class="w-full"> + Download PDF diff --git a/resources/views/print/report.blade.php b/resources/views/print/report.blade.php new file mode 100644 index 0000000..323abc2 --- /dev/null +++ b/resources/views/print/report.blade.php @@ -0,0 +1,254 @@ + + + + + Laporan Hasil Belajar + + + + +
+

Laporan Hasil Belajar

+

(RAPOR)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Nama Peserta Didik: {{ $student->full_name }}Kelas: {{ $class_name }}
NISN/NIS: {{ $student->nisn }} / {{ $student->nis }}Fase: -
Sekolah: {{ $school_information->school_name }}Semester: {{ $semester === 'first' ? "I" : "II"}}
Alamat: {{ $school_information->address }}Tahun Ajaran: {{ $academic_year->name }}
+ + @php + $i = 1; + @endphp + + + + + + + + @if(!empty($table['assessments']['umum'])) + @foreach($table['assessments']['umum'] as $subjects => $subject) + + + + + + + @php + $i++; + @endphp + @endforeach + @endif + + @if(!empty($table['assessments']['seni'])) + + + + + @php $charIndex = 0; @endphp + @foreach($table['assessments']['seni'] as $subjects => $subject) + + + + + + + @php + $i++; + @endphp + @endforeach + @endif + +
NoMuatan PelajaranNilai AkhirCapaian Kompetensi
{{ $i }}{{ $subject["subject"] }}{{ $subject["score"] }}{{ $subject["competency_achievement"] }}
{{ $i }}Seni
{{ chr(97 + $charIndex) }}{{ $subject["subject"] }}{{ $subject["score"] }}{{ $subject["competency_achievement"] }}
+ +
Muatan Lokal + + + + + + + + @if(!empty($table['assessments']['muatan lokal'])) + @foreach($table['assessments']['muatan lokal'] as $subjects => $subject) + + + + + + + @php + $i++; + @endphp + @endforeach + @endif +
NoMuatan PelajaranNilai AkhirCapaian Kompetensi
{{ $i }}{{ $subject["subject"] }}{{ $subject["score"] }}{{ $subject["competency_achievement"] }}
+ + + + + + + + + @php + $i = 1; + @endphp + @if(!empty($table["extracurricular"])) + + @foreach($table['extracurricular'] as $subjects => $subject) + + + + + + + @php + $i++; + @endphp + @endforeach + @else + + + + + + + @endif +
NoEkstrakurikulerPredikatKeterangan
{{ $i }}{{ $subject["name"] }}{{ $subject["predicate"] }}{{ $subject["description"] }}
+ + + + + + + + +
+ Ketidakhadiran +
Sakit: {{ $sakit ?? 0 }} hari
Izin: {{ $izin ?? 0 }} hari
Tanpa Keterangan: {{ $tanpa_keterangan ?? 0 }} hari
+ +
+ + + + + +
+ Orang Tua / Wali



+ +
+ @php + \Carbon\Carbon::setLocale('id'); + @endphp + Depok, {{ \Carbon\Carbon::now()->translatedFormat('d F Y') }}
+ Wali Kelas {{ $class_name }}


+ {{ $home_room_teacher["teacher"]["name"] ?? '-' }}
+ NIP. {{ $home_room_teacher["teacher"]["nip"] ?? '-' }} +
+ +
+ Mengetahui,
+ Kepala Sekolah


+ {{ $school_information->headmaster_name }}
+ NIP: {{ $school_information->headmaster_nip }} +
+ + + diff --git a/routes/web.php b/routes/web.php index 86a06c5..6c55e9b 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,7 +1,10 @@ name('report.pdf');