diff --git a/catatan_rilis.md b/catatan_rilis.md
index 72f31e9a..ab6f9457 100644
--- a/catatan_rilis.md
+++ b/catatan_rilis.md
@@ -15,4 +15,5 @@ Di rilis ini, versi 2601.0.0 berisi penambahan dan perbaikan yang diminta penggu
#### Perubahan Teknis
1. [#892](https://github.com/OpenSID/OpenKab/issues/892) Perbaikan tag style agar tidak dianggap error ketika csp aktif.
-2. [#886](https://github.com/OpenSID/OpenKab/issues/886) Ubah label cetak menjadi excel pada laporan bulanan.
\ No newline at end of file
+2. [#886](https://github.com/OpenSID/OpenKab/issues/886) Ubah label cetak menjadi excel pada laporan bulanan.
+3. [#903](https://github.com/OpenSID/OpenKab/issues/903) Ubah fungsi cetak ke expor excel pada halaman rincian kependudukan bulanan.
\ No newline at end of file
diff --git a/resources/views/laporan-bulanan/detail/index.blade.php b/resources/views/laporan-bulanan/detail/index.blade.php
index e68aadf1..0497ab27 100644
--- a/resources/views/laporan-bulanan/detail/index.blade.php
+++ b/resources/views/laporan-bulanan/detail/index.blade.php
@@ -3,7 +3,7 @@
@section('title', $page_title ?? 'Page Title')
@section('content_header')
-
{{ $page_description ?? '' }}
+{{ $page_description ?? '' }}
@stop
@section('content')
@@ -15,9 +15,9 @@
-
- Cetak
+ class="btn btn-success btn-sm">
+
+ Export Excel
@@ -58,7 +58,7 @@ class="btn btn-primary btn-sm">
const header = @include('layouts.components.header_bearer_api_gabungan');
var url = new URL("{{ config('app.databaseGabunganUrl') . '/api/v1/statistik/laporan-bulanan/sumber-data' }}");
- document.addEventListener("DOMContentLoaded", function(event) {
+ document.addEventListener("DOMContentLoaded", function (event) {
let nama_desa = `{{ session('desa.nama_desa') }}`;
var penduduk = $('#detail_penduduk').DataTable({
processing: true,
@@ -74,13 +74,13 @@ class="btn btn-primary btn-sm">
url: url.href,
method: 'get',
headers: header,
- data: function(row) {
+ data: function (row) {
return {
"page[size]": row.length,
"page[number]": (row.start / row.length) + 1,
"filter[search]": row.search.value,
"sort": (row.order[0]?.dir === "asc" ? "" : "-") + row.columns[row.order[0]
- ?.column]
+ ?.column]
?.name,
'filter[rincian]': '{{ $rincian }}',
'filter[tipe]': '{{ $tipe }}',
@@ -94,7 +94,7 @@ class="btn btn-primary btn-sm">
'kode_desa': '{{ $kode_desa }}',
};
},
- dataSrc: function(json) {
+ dataSrc: function (json) {
json.recordsTotal = json.meta.pagination.total
json.recordsFiltered = json.meta.pagination.total
@@ -102,63 +102,63 @@ class="btn btn-primary btn-sm">
},
},
columnDefs: [{
- targets: '_all',
- className: 'text-nowrap',
- },
- {
- targets: [0, 1, 4, 5, 6],
- orderable: false,
- searchable: false,
- },
+ targets: '_all',
+ className: 'text-nowrap',
+ },
+ {
+ targets: [0, 1, 4, 5, 6],
+ orderable: false,
+ searchable: false,
+ },
],
columns: [{
- data: null,
- },
- {
- data: "attributes.nama",
- name: "nama",
- defaultContent: '-',
- },
- {
- data: "attributes.nik",
- name: "nik",
- defaultContent: '-',
- },
- {
- data: "attributes.tempatlahir",
- searcable: false,
- className: 'text-center',
- defaultContent: '-',
- },
- {
- data: function(data) {
- return data.attributes.tanggallahir ?? '';
- },
- },
- {
- data: "attributes.nama_ayah",
- name: "nama_ayah",
- defaultContent: '-',
- },
- {
- data: "attributes.nama_ibu",
- name: "nama_ibu",
- defaultContent: '-',
+ data: null,
+ },
+ {
+ data: "attributes.nama",
+ name: "nama",
+ defaultContent: '-',
+ },
+ {
+ data: "attributes.nik",
+ name: "nik",
+ defaultContent: '-',
+ },
+ {
+ data: "attributes.tempatlahir",
+ searcable: false,
+ className: 'text-center',
+ defaultContent: '-',
+ },
+ {
+ data: function (data) {
+ return data.attributes.tanggallahir ?? '';
},
+ },
+ {
+ data: "attributes.nama_ayah",
+ name: "nama_ayah",
+ defaultContent: '-',
+ },
+ {
+ data: "attributes.nama_ibu",
+ name: "nama_ibu",
+ defaultContent: '-',
+ },
],
order: [
[2, 'asc']
]
})
- penduduk.on('draw.dt', function() {
+ penduduk.on('draw.dt', function () {
var PageInfo = $('#detail_penduduk').DataTable().page.info();
penduduk.column(0, {
page: 'current'
- }).nodes().each(function(cell, i) {
+ }).nodes().each(function (cell, i) {
cell.innerHTML = i + 1 + PageInfo.start;
});
});
});
-@endsection
+@endsection
\ No newline at end of file
diff --git a/tests/Feature/LaporanBulananDetailExportTest.php b/tests/Feature/LaporanBulananDetailExportTest.php
new file mode 100644
index 00000000..d8eafa6c
--- /dev/null
+++ b/tests/Feature/LaporanBulananDetailExportTest.php
@@ -0,0 +1,58 @@
+ 1,
+ 'tahunku' => 2026,
+ 'kode_kabupaten' => '35',
+ ]);
+
+ $response = $this->get(route('laporan-bulanan.detail-penduduk', [
+ 'rincian' => 'awal',
+ 'tipe' => 'wni_l',
+ ]));
+
+ $response->assertStatus(200);
+ $content = $response->getContent();
+
+ // Verifikasi tombol Export Excel ada dengan icon dan class yang benar
+ $this->assertStringContainsString('fa-file-excel', $content, 'Icon Excel tidak ditemukan');
+ $this->assertStringContainsString('Export Excel', $content, 'Label Export Excel tidak ditemukan');
+ $this->assertStringContainsString('btn-success', $content, 'Class btn-success tidak ditemukan');
+
+ // Verifikasi tombol lama (Cetak) sudah tidak ada
+ $this->assertStringNotContainsString('fa-print', $content, 'Icon print seharusnya sudah dihapus');
+ $this->assertStringNotContainsString('>Cetak<', $content, 'Label Cetak seharusnya sudah dihapus');
+ }
+
+ /** @test */
+ public function test_detail_page_export_excel_button_has_correct_route()
+ {
+ session([
+ 'bulanku' => 1,
+ 'tahunku' => 2026,
+ 'kode_kabupaten' => '35',
+ ]);
+
+ $response = $this->get(route('laporan-bulanan.detail-penduduk', [
+ 'rincian' => 'lahir',
+ 'tipe' => 'wni_p',
+ ]));
+
+ $response->assertStatus(200);
+ $content = $response->getContent();
+
+ // Verifikasi URL export ada dengan parameter yang benar
+ $expectedRoutePattern = 'laporan-bulanan/export-excel-detail/lahir/wni_p';
+ $this->assertStringContainsString($expectedRoutePattern, $content, 'Route export excel detail tidak ditemukan');
+ }
+}