diff --git a/app/Http/Controllers/Admin/ViolationReportController.php b/app/Http/Controllers/Admin/ViolationReportController.php
new file mode 100644
index 0000000..e095fbd
--- /dev/null
+++ b/app/Http/Controllers/Admin/ViolationReportController.php
@@ -0,0 +1,96 @@
+get();
+
+ $query = Violation::query()
+ ->when(auth()->user()->isScopedWaliKelas(), fn ($q) => $q->whereHas('student', fn ($qq) => $qq->whereIn('class_id', auth()->user()->homeroomClassIds())));
+
+ $totalKasus = (clone $query)->count();
+ $totalPoin = (clone $query)->sum('points');
+ $siswaTerlibat = (clone $query)->distinct('student_id')->count('student_id');
+
+ return view('reports.violations', compact('classes', 'totalKasus', 'totalPoin', 'siswaTerlibat'));
+ }
+
+ public function pdf(Request $request)
+ {
+ $data = $request->validate([
+ 'date_from' => ['nullable', 'date'],
+ 'date_to' => ['nullable', 'date', 'after_or_equal:date_from'],
+ 'class_id' => ['nullable', 'exists:classes,id'],
+ ]);
+
+ $query = Violation::with(['student.class', 'violationType.category', 'handlings'])
+ ->when($data['date_from'] ?? null, fn ($q) => $q->whereDate('violation_date', '>=', $data['date_from']))
+ ->when($data['date_to'] ?? null, fn ($q) => $q->whereDate('violation_date', '<=', $data['date_to']))
+ ->when($data['class_id'] ?? null, fn ($q) => $q->whereHas('student', fn ($qq) => $qq->where('class_id', $data['class_id'])))
+ // Wali kelas murni: hanya kelas yang diwalikan
+ ->when(auth()->user()->isScopedWaliKelas(), fn ($q) => $q->whereHas('student', fn ($qq) => $qq->whereIn('class_id', auth()->user()->homeroomClassIds())));
+
+ $violations = $query->orderBy('violation_date')->get();
+
+ $summary = [
+ 'total_kasus' => $violations->count(),
+ 'total_poin' => $violations->sum('points'),
+ 'siswa_terlibat' => $violations->pluck('student_id')->unique()->count(),
+ ];
+
+ $perJenis = $violations->groupBy(fn ($v) => $v->violationType?->name ?? 'Tanpa Jenis')
+ ->map(fn ($group) => [
+ 'jenis' => $group->first()->violationType?->name ?? 'Tanpa Jenis',
+ 'kategori' => $group->first()->violationType?->category?->name ?? '-',
+ 'jumlah' => $group->count(),
+ 'poin' => $group->sum('points'),
+ ])
+ ->sortByDesc('jumlah')
+ ->values();
+
+ $perKelas = $violations->groupBy(fn ($v) => $v->student?->class?->name ?? 'Tanpa Kelas')
+ ->map(fn ($group) => [
+ 'kelas' => $group->first()->student?->class?->name ?? 'Tanpa Kelas',
+ 'jumlah' => $group->count(),
+ 'poin' => $group->sum('points'),
+ ])
+ ->sortByDesc('jumlah')
+ ->values();
+
+ $school = [
+ 'name' => Setting::getValue('school_name', 'SMK'),
+ 'address' => Setting::getValue('school_address', ''),
+ 'phone' => Setting::getValue('school_phone', ''),
+ 'logo' => Setting::getValue('school_logo', ''),
+ 'kepala_sekolah' => Setting::getValue('kepala_sekolah_name', ''),
+ 'kepala_sekolah_nip' => Setting::getValue('kepala_sekolah_nip', ''),
+ ];
+
+ $periode = ($data['date_from'] ?? 'Awal').' s/d '.($data['date_to'] ?? 'Sekarang');
+ $filterKelas = $data['class_id'] ?? null
+ ? Classes::find($data['class_id'])?->name
+ : 'Semua Kelas';
+
+ $pdf = Pdf::loadView('reports.violation-report-pdf', compact(
+ 'violations', 'summary', 'perJenis', 'perKelas', 'school', 'periode', 'filterKelas'
+ ))->setPaper('a4', 'landscape');
+
+ $filename = 'rekap-pelanggaran-'.now()->format('Ymd-His').'.pdf';
+
+ return $pdf->download($filename);
+ }
+}
diff --git a/composer.json b/composer.json
index fc78dc4..6314533 100644
--- a/composer.json
+++ b/composer.json
@@ -7,6 +7,7 @@
"license": "MIT",
"require": {
"php": "^8.3",
+ "barryvdh/laravel-dompdf": "^3.1",
"laravel/framework": "^13.8",
"laravel/reverb": "^1.10",
"laravel/tinker": "^3.0",
diff --git a/composer.lock b/composer.lock
index da4fbd8..855f113 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,85 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "201a8d1d916055d461ce40221c866999",
+ "content-hash": "afdc1f6e4dfd50c7b92edd5a03dbc47e",
"packages": [
+ {
+ "name": "barryvdh/laravel-dompdf",
+ "version": "v3.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/barryvdh/laravel-dompdf.git",
+ "reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/ee3b72b19ccdf57d0243116ecb2b90261344dedc",
+ "reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc",
+ "shasum": ""
+ },
+ "require": {
+ "dompdf/dompdf": "^3.0",
+ "illuminate/support": "^9|^10|^11|^12|^13.0",
+ "php": "^8.1"
+ },
+ "require-dev": {
+ "larastan/larastan": "^2.7|^3.0",
+ "orchestra/testbench": "^7|^8|^9.16|^10|^11.0",
+ "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.2"
+ },
+ "funding": [
+ {
+ "url": "https://fruitcake.nl",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/barryvdh",
+ "type": "github"
+ }
+ ],
+ "time": "2026-02-21T08:51:10+00:00"
+ },
{
"name": "brick/math",
"version": "0.18.0",
@@ -582,6 +659,161 @@
],
"time": "2024-02-05T11:56:58+00:00"
},
+ {
+ "name": "dompdf/dompdf",
+ "version": "v3.1.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/dompdf/dompdf.git",
+ "reference": "6d4b4eb8500f7a786da8868ba463a71b725a4005"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/dompdf/dompdf/zipball/6d4b4eb8500f7a786da8868ba463a71b725a4005",
+ "reference": "6d4b4eb8500f7a786da8868ba463a71b725a4005",
+ "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.6"
+ },
+ "time": "2026-07-20T12:29:38+00:00"
+ },
+ {
+ "name": "dompdf/php-font-lib",
+ "version": "1.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/dompdf/php-font-lib.git",
+ "reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/a6e9a688a2a80016ac080b97be73d3e10c444c9a",
+ "reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11 || ^12"
+ },
+ "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.2"
+ },
+ "time": "2026-01-20T14:10:26+00:00"
+ },
+ {
+ "name": "dompdf/php-svg-lib",
+ "version": "1.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/dompdf/php-svg-lib.git",
+ "reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8259ffb930817e72b1ff1caef5d226501f3dfeb1",
+ "reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": "^7.1 || ^8.0",
+ "sabberworm/php-css-parser": "^8.4 || ^9.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11"
+ },
+ "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.2"
+ },
+ "time": "2026-01-02T16:01:13+00:00"
+ },
{
"name": "dragonmantank/cron-expression",
"version": "v3.6.0",
@@ -2549,6 +2781,73 @@
},
"time": "2022-12-02T22:17:43+00:00"
},
+ {
+ "name": "masterminds/html5",
+ "version": "2.10.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Masterminds/html5-php.git",
+ "reference": "fd5018f6815fff903946d0564977b44ce8010e29"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fd5018f6815fff903946d0564977b44ce8010e29",
+ "reference": "fd5018f6815fff903946d0564977b44ce8010e29",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9 || ^10"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.7-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Masterminds\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Matt Butcher",
+ "email": "technosophos@gmail.com"
+ },
+ {
+ "name": "Matt Farina",
+ "email": "matt@mattfarina.com"
+ },
+ {
+ "name": "Asmir Mustafic",
+ "email": "goetas@gmail.com"
+ }
+ ],
+ "description": "An HTML5 parser and serializer.",
+ "homepage": "http://masterminds.github.io/html5-php",
+ "keywords": [
+ "HTML5",
+ "dom",
+ "html",
+ "parser",
+ "querypath",
+ "serializer",
+ "xml"
+ ],
+ "support": {
+ "issues": "https://github.com/Masterminds/html5-php/issues",
+ "source": "https://github.com/Masterminds/html5-php/tree/2.10.1"
+ },
+ "time": "2026-06-23T18:43:15+00:00"
+ },
{
"name": "monolog/monolog",
"version": "3.10.0",
@@ -4581,6 +4880,86 @@
],
"time": "2024-06-11T12:45:25+00:00"
},
+ {
+ "name": "sabberworm/php-css-parser",
+ "version": "v9.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
+ "reference": "fd3bf9fb173e0df649bc4e3e0d088a1b2417c08f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/fd3bf9fb173e0df649bc4e3e0d088a1b2417c08f",
+ "reference": "fd3bf9fb173e0df649bc4e3e0d088a1b2417c08f",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
+ "thecodingmachine/safe": "^1.3 || ^2.5 || ^3.4"
+ },
+ "require-dev": {
+ "php-parallel-lint/php-parallel-lint": "1.4.0",
+ "phpstan/extension-installer": "1.4.3",
+ "phpstan/phpstan": "1.12.33 || 2.2.2",
+ "phpstan/phpstan-phpunit": "1.4.2 || 2.0.16",
+ "phpstan/phpstan-strict-rules": "1.6.2 || 2.0.11",
+ "phpunit/phpunit": "8.5.52",
+ "rawr/phpunit-data-provider": "3.3.1",
+ "rector/rector": "1.2.10 || 2.4.6",
+ "rector/type-perfect": "1.0.0 || 2.1.3",
+ "squizlabs/php_codesniffer": "4.0.1",
+ "thecodingmachine/phpstan-safe-rule": "1.2.0 || 1.4.3"
+ },
+ "suggest": {
+ "ext-mbstring": "for parsing UTF-8 CSS"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "9.5.x-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/Rule/Rule.php",
+ "src/RuleSet/RuleContainer.php"
+ ],
+ "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/v9.4.0"
+ },
+ "time": "2026-06-18T15:10:53+00:00"
+ },
{
"name": "symfony/clock",
"version": "v8.1.0",
@@ -7060,6 +7439,149 @@
],
"time": "2026-06-09T10:54:51+00:00"
},
+ {
+ "name": "thecodingmachine/safe",
+ "version": "v3.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thecodingmachine/safe.git",
+ "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19",
+ "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.1"
+ },
+ "require-dev": {
+ "php-parallel-lint/php-parallel-lint": "^1.4",
+ "phpstan/phpstan": "^2",
+ "phpunit/phpunit": "^10",
+ "squizlabs/php_codesniffer": "^3.2"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "lib/special_cases.php",
+ "generated/apache.php",
+ "generated/apcu.php",
+ "generated/array.php",
+ "generated/bzip2.php",
+ "generated/calendar.php",
+ "generated/classobj.php",
+ "generated/com.php",
+ "generated/cubrid.php",
+ "generated/curl.php",
+ "generated/datetime.php",
+ "generated/dir.php",
+ "generated/eio.php",
+ "generated/errorfunc.php",
+ "generated/exec.php",
+ "generated/fileinfo.php",
+ "generated/filesystem.php",
+ "generated/filter.php",
+ "generated/fpm.php",
+ "generated/ftp.php",
+ "generated/funchand.php",
+ "generated/gettext.php",
+ "generated/gmp.php",
+ "generated/gnupg.php",
+ "generated/hash.php",
+ "generated/ibase.php",
+ "generated/ibmDb2.php",
+ "generated/iconv.php",
+ "generated/image.php",
+ "generated/imap.php",
+ "generated/info.php",
+ "generated/inotify.php",
+ "generated/json.php",
+ "generated/ldap.php",
+ "generated/libxml.php",
+ "generated/lzf.php",
+ "generated/mailparse.php",
+ "generated/mbstring.php",
+ "generated/misc.php",
+ "generated/mysql.php",
+ "generated/mysqli.php",
+ "generated/network.php",
+ "generated/oci8.php",
+ "generated/opcache.php",
+ "generated/openssl.php",
+ "generated/outcontrol.php",
+ "generated/pcntl.php",
+ "generated/pcre.php",
+ "generated/pgsql.php",
+ "generated/posix.php",
+ "generated/ps.php",
+ "generated/pspell.php",
+ "generated/readline.php",
+ "generated/rnp.php",
+ "generated/rpminfo.php",
+ "generated/rrd.php",
+ "generated/sem.php",
+ "generated/session.php",
+ "generated/shmop.php",
+ "generated/sockets.php",
+ "generated/sodium.php",
+ "generated/solr.php",
+ "generated/spl.php",
+ "generated/sqlsrv.php",
+ "generated/ssdeep.php",
+ "generated/ssh2.php",
+ "generated/stream.php",
+ "generated/strings.php",
+ "generated/swoole.php",
+ "generated/uodbc.php",
+ "generated/uopz.php",
+ "generated/url.php",
+ "generated/var.php",
+ "generated/xdiff.php",
+ "generated/xml.php",
+ "generated/xmlrpc.php",
+ "generated/yaml.php",
+ "generated/yaz.php",
+ "generated/zip.php",
+ "generated/zlib.php"
+ ],
+ "classmap": [
+ "lib/DateTime.php",
+ "lib/DateTimeImmutable.php",
+ "lib/Exceptions/",
+ "generated/Exceptions/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHP core functions that throw exceptions instead of returning FALSE on error",
+ "support": {
+ "issues": "https://github.com/thecodingmachine/safe/issues",
+ "source": "https://github.com/thecodingmachine/safe/tree/v3.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/OskarStark",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/shish",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/silasjoisten",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/staabm",
+ "type": "github"
+ }
+ ],
+ "time": "2026-02-04T18:08:13+00:00"
+ },
{
"name": "tijsverkoyen/css-to-inline-styles",
"version": "v2.4.0",
@@ -9561,12 +10083,12 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
"php": "^8.3"
},
- "platform-dev": [],
- "plugin-api-version": "2.6.0"
+ "platform-dev": {},
+ "plugin-api-version": "2.9.0"
}
diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php
index c4ceb07..d4e1faa 100644
--- a/database/factories/UserFactory.php
+++ b/database/factories/UserFactory.php
@@ -26,6 +26,7 @@ class UserFactory extends Factory
{
return [
'name' => fake()->name(),
+ 'username' => fake()->unique()->userName(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),
diff --git a/database/migrations/2026_07_22_164059_add_is_system_to_violation_types_table.php b/database/migrations/2026_07_22_164059_add_is_system_to_violation_types_table.php
index d07eb5e..2c29367 100644
--- a/database/migrations/2026_07_22_164059_add_is_system_to_violation_types_table.php
+++ b/database/migrations/2026_07_22_164059_add_is_system_to_violation_types_table.php
@@ -13,13 +13,14 @@ return new class extends Migration
});
// Mark existing alpha & terlambat types as system
+ // (ambil id dulu — MySQL 8 menolak UPDATE..SELECT dari tabel yang sama)
+ $systemIds = DB::table('violation_types')
+ ->where('name', 'like', '%alpha%')
+ ->orWhere('slug', 'terlambat-datang-ke-sekolah-1')
+ ->pluck('id');
+
DB::table('violation_types')
- ->whereIn('id', function ($q) {
- $q->select('id')
- ->from('violation_types')
- ->where('name', 'like', '%alpha%')
- ->orWhere('slug', 'terlambat-datang-ke-sekolah-1');
- })
+ ->whereIn('id', $systemIds)
->update(['is_system' => true]);
// Set clean slugs for system types
diff --git a/phpunit.xml b/phpunit.xml
index e7f0a48..cdd1588 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -23,8 +23,12 @@
Master Data
diff --git a/resources/views/reports/violation-report-pdf.blade.php b/resources/views/reports/violation-report-pdf.blade.php new file mode 100644 index 0000000..77cfa4f --- /dev/null +++ b/resources/views/reports/violation-report-pdf.blade.php @@ -0,0 +1,180 @@ + + + + +Periode: {{ $periode }} • Kelas: {{ $filterKelas }}
+| {{ $summary['total_kasus'] }}Total Kasus | +{{ $summary['total_poin'] }}Total Poin | +{{ $summary['siswa_terlibat'] }}Siswa Terlibat | +
| No | +Jenis Pelanggaran | +Kategori | +Jumlah | +Total Poin | +
|---|---|---|---|---|
| {{ $i + 1 }} | +{{ $item['jenis'] }} | +{{ $item['kategori'] }} | +{{ $item['jumlah'] }} | +{{ $item['poin'] }} | +
| Tidak ada data | ||||
| No | +Kelas | +Jumlah | +Total Poin | +
|---|---|---|---|
| {{ $i + 1 }} | +{{ $item['kelas'] }} | +{{ $item['jumlah'] }} | +{{ $item['poin'] }} | +
| Tidak ada data | |||
| No | +Tanggal | +NISN | +Nama Siswa | +Kelas | +Jenis Pelanggaran | +Poin | +Status | +
|---|---|---|---|---|---|---|---|
| {{ $i + 1 }} | +{{ $v->violation_date?->format('d/m/Y') }} | +{{ $v->student?->nisn }} | +{{ $v->student?->full_name }} | +{{ $v->student?->class?->name }} | +{{ $v->violationType?->name }} ({{ $v->violationType?->category?->name ?? '-' }}) | +{{ $v->points }} | +{{ $status }} | +
| Tidak ada data pelanggaran pada periode ini | |||||||
|
+ Petugas / Guru BK
+ ______________________
+ |
+
+ Mengetahui,
+ Kepala {{ $school['name'] }} {{ $school['kepala_sekolah'] }}
+ NIP. {{ $school['kepala_sekolah_nip'] }}
+ |
+
Cetak rekap pelanggaran per periode untuk BK & Kepala Sekolah
+