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
+
+
+ | No |
+ Muatan Pelajaran |
+ Nilai Akhir |
+ Capaian Kompetensi |
+
+ @if(!empty($table['assessments']['umum']))
+ @foreach($table['assessments']['umum'] as $subjects => $subject)
+
+ | {{ $i }} |
+ {{ $subject["subject"] }} |
+ {{ $subject["score"] }} |
+ {{ $subject["competency_achievement"] }} |
+
+ @php
+ $i++;
+ @endphp
+ @endforeach
+ @endif
+
+ @if(!empty($table['assessments']['seni']))
+
+ | {{ $i }} |
+ Seni |
+
+ @php $charIndex = 0; @endphp
+ @foreach($table['assessments']['seni'] as $subjects => $subject)
+
+ | {{ chr(97 + $charIndex) }} |
+ {{ $subject["subject"] }} |
+ {{ $subject["score"] }} |
+ {{ $subject["competency_achievement"] }} |
+
+ @php
+ $i++;
+ @endphp
+ @endforeach
+ @endif
+
+
+
+
Muatan Lokal
+
+
+ | No |
+ Muatan Pelajaran |
+ Nilai Akhir |
+ Capaian Kompetensi |
+
+ @if(!empty($table['assessments']['muatan lokal']))
+ @foreach($table['assessments']['muatan lokal'] as $subjects => $subject)
+
+ | {{ $i }} |
+ {{ $subject["subject"] }} |
+ {{ $subject["score"] }} |
+ {{ $subject["competency_achievement"] }} |
+
+ @php
+ $i++;
+ @endphp
+ @endforeach
+ @endif
+
+
+
+
+ | No |
+ Ekstrakurikuler |
+ Predikat |
+ Keterangan |
+
+ @php
+ $i = 1;
+ @endphp
+ @if(!empty($table["extracurricular"]))
+
+ @foreach($table['extracurricular'] as $subjects => $subject)
+
+ | {{ $i }} |
+ {{ $subject["name"] }} |
+ {{ $subject["predicate"] }} |
+ {{ $subject["description"] }} |
+
+ @php
+ $i++;
+ @endphp
+ @endforeach
+ @else
+
+ |
+ |
+ |
+ |
+
+ @endif
+
+
+
+
+ |
+ 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');