From 088f173fec059bda90fb932b19ad03698bcfd308 Mon Sep 17 00:00:00 2001 From: arifal Date: Thu, 20 Mar 2025 20:12:42 +0700 Subject: [PATCH] fix add params filter date on grid js, export excel and pdf payment recaps --- app/Exports/ReportPaymentRecapExport.php | 71 +++++ .../Api/BigDataResumeController.php | 76 +++++- resources/js/payment-recaps/index.js | 258 ++++++++++++++---- .../exports/payment_recaps_report.blade.php | 35 +++ .../views/payment-recaps/index.blade.php | 13 + routes/api.php | 2 + 6 files changed, 400 insertions(+), 55 deletions(-) create mode 100644 app/Exports/ReportPaymentRecapExport.php create mode 100644 resources/views/exports/payment_recaps_report.blade.php diff --git a/app/Exports/ReportPaymentRecapExport.php b/app/Exports/ReportPaymentRecapExport.php new file mode 100644 index 0000000..a92ad96 --- /dev/null +++ b/app/Exports/ReportPaymentRecapExport.php @@ -0,0 +1,71 @@ +startDate = $startDate; + $this->endDate = $endDate; + } + public function collection() + { + $query = BigdataResume::query()->orderBy('id', 'desc'); + + if ($this->startDate && $this->endDate) { + $query->whereBetween('created_at', [$this->startDate, $this->endDate]); + } + + $items = $query->get(); + + $categoryMap = [ + 'potention_sum' => 'Potensi', + 'non_verified_sum' => 'Belum Terverifikasi', + 'verified_sum' => 'Terverifikasi', + 'business_sum' => 'Usaha', + 'non_business_sum' => 'Non Usaha', + 'spatial_sum' => 'Tata Ruang', + 'waiting_click_dpmptsp_sum' => 'Menunggu Klik DPMPTSP', + 'issuance_realization_pbg_sum' => 'Realisasi Terbit PBG', + 'process_in_technical_office_sum' => 'Proses Di Dinas Teknis', + ]; + + // Restructure response + $data = []; + + foreach ($items as $item) { + $createdAt = $item->created_at; + $id = $item->id; + + foreach ($item->toArray() as $key => $value) { + // Only include columns with "sum" in their names + if (strpos($key, 'sum') !== false) { + $data[] = [ + 'category' => $categoryMap[$key] ?? $key, // Map category + 'nominal' => number_format($value, 0, ',', '.'), // Format number + 'created_at' => $createdAt->format('Y-m-d H:i:s'), // Format date + ]; + } + } + } + + return collect($data); + } + + public function headings(): array{ + return [ + 'Kategori', + 'Nominal', + 'Created' + ]; + } +} diff --git a/app/Http/Controllers/Api/BigDataResumeController.php b/app/Http/Controllers/Api/BigDataResumeController.php index 84022d4..5b68fbd 100644 --- a/app/Http/Controllers/Api/BigDataResumeController.php +++ b/app/Http/Controllers/Api/BigDataResumeController.php @@ -3,11 +3,13 @@ namespace App\Http\Controllers\Api; use App\Exports\ReportDirectorExport; +use App\Exports\ReportPaymentRecapExport; use App\Http\Controllers\Controller; use App\Http\Resources\BigdataResumeResource; use App\Models\BigdataResume; use App\Models\DataSetting; use Barryvdh\DomPDF\Facade\Pdf; +use Carbon\Carbon; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Maatwebsite\Excel\Facades\Excel; @@ -181,11 +183,14 @@ class BigDataResumeController extends Controller try { $query = BigdataResume::query()->orderBy('id', 'desc'); - if ($request->filled('date')) { - $query->where('year', 'LIKE', '%' . $request->input('search') . '%'); + if ($request->filled('start_date') && $request->filled('end_date')) { + $startDate = Carbon::parse($request->input('start_date'))->startOfDay(); + $endDate = Carbon::parse($request->input('end_date'))->endOfDay(); + + $query->whereBetween('created_at', [$startDate, $endDate]); } - $data = $query->paginate(10); + $data = $query->paginate(50); // Restructure response $transformedData = []; @@ -210,7 +215,7 @@ class BigDataResumeController extends Controller return response()->json([ 'data' => $transformedData, // Flat array 'pagination' => [ - 'total' => $data->total(), + 'total' => count($transformedData), 'per_page' => $data->perPage(), 'current_page' => $data->currentPage(), 'last_page' => $data->lastPage(), @@ -222,6 +227,69 @@ class BigDataResumeController extends Controller } } + public function export_excel_payment_recaps(Request $request) + { + $startDate = null; + $endDate = null; + + if ($request->filled('start_date') && $request->filled('end_date')) { + $startDate = Carbon::parse($request->input('start_date'))->startOfDay(); + $endDate = Carbon::parse($request->input('end_date'))->endOfDay(); + } + + return Excel::download(new ReportPaymentRecapExport($startDate, $endDate), 'laporan-rekap-pembayaran.xlsx'); + } + + public function export_pdf_payment_recaps(Request $request){ + $query = BigdataResume::query()->orderBy('id', 'desc'); + + if ($request->filled('start_date') && $request->filled('end_date')) { + $startDate = Carbon::parse($request->input('start_date'))->startOfDay(); + $endDate = Carbon::parse($request->input('end_date'))->endOfDay(); + + $query->whereBetween('created_at', [$startDate, $endDate]); + } + + $items = $query->get(); + + // Define category mapping + $categoryMap = [ + 'potention_sum' => 'Potensi', + 'non_verified_sum' => 'Belum Terverifikasi', + 'verified_sum' => 'Terverifikasi', + 'business_sum' => 'Usaha', + 'non_business_sum' => 'Non Usaha', + 'spatial_sum' => 'Tata Ruang', + 'waiting_click_dpmptsp_sum' => 'Menunggu Klik DPMPTSP', + 'issuance_realization_pbg_sum' => 'Realisasi Terbit PBG', + 'process_in_technical_office_sum' => 'Proses Di Dinas Teknis', + ]; + + // Restructure response + $data = []; + + foreach ($items as $item) { + $createdAt = $item->created_at; + $id = $item->id; + + foreach ($item->toArray() as $key => $value) { + // Only include columns with "sum" in their names + if (strpos($key, 'sum') !== false) { + $data[] = [ + 'id' => $id, + 'category' => $categoryMap[$key] ?? $key, // Map category + 'nominal' => $value, // Format number + 'created_at' => $createdAt->format('Y-m-d H:i:s'), // Format date + ]; + } + } + } + + $pdf = Pdf::loadView('exports.payment_recaps_report', compact('data')); + return $pdf->download('laporan-rekap-pembayaran.pdf'); + } + + public function export_excel_report_director(){ return Excel::download(new ReportDirectorExport, 'laporan-pimpinan.xlsx'); } diff --git a/resources/js/payment-recaps/index.js b/resources/js/payment-recaps/index.js index 0062233..69e6e18 100644 --- a/resources/js/payment-recaps/index.js +++ b/resources/js/payment-recaps/index.js @@ -11,8 +11,15 @@ class PaymentRecaps { this.toastElement = document.getElementById("toastNotification"); this.toast = new bootstrap.Toast(this.toastElement); this.table = null; + this.startDate = undefined; + this.endDate = undefined; + } + init() { this.initTablePaymentRecaps(); this.initFilterDatepicker(); + this.handleFilterBtn(); + this.handleExportPDF(); + this.handleExportToExcel(); } initFilterDatepicker() { new InitDatePicker( @@ -20,8 +27,13 @@ class PaymentRecaps { this.handleChangeFilterDate.bind(this) ).init(); } - handleChangeFilterDate(strDate) { - console.log("filter date : ", strDate); + handleChangeFilterDate(filterDate) { + this.startDate = moment(filterDate, "YYYY-MM-DD") + .startOf("day") + .format("YYYY-MM-DD"); + this.endDate = moment(filterDate, "YYYY-MM-DD") + .endOf("day") + .format("YYYY-MM-DD"); } formatCategory(category) { const categoryMap = { @@ -41,64 +53,208 @@ class PaymentRecaps { initTablePaymentRecaps() { let tableContainer = document.getElementById("table-payment-recaps"); - this.table = new Grid({ - columns: [ - { name: "Kategori", data: (row) => row[0] }, - { name: "Nominal", data: (row) => row[1] }, - { - name: "Created", - data: (row) => row[2], - attributes: { style: "width: 200px; white-space: nowrap;" }, - }, - ], - pagination: { - limit: 10, - server: { - url: (prev, page) => - `${prev}${prev.includes("?") ? "&" : "?"}page=${ - page + 1 - }`, - }, - }, - sort: true, - server: { - url: `${GlobalConfig.apiHost}/api/payment-recaps`, + // Fetch data from the server + fetch( + `${GlobalConfig.apiHost}/api/payment-recaps?start_date=${ + this.startDate || "" + }&end_date=${this.endDate || ""}`, + { headers: { Authorization: `Bearer ${document .querySelector('meta[name="api-token"]') .getAttribute("content")}`, "Content-Type": "application/json", }, - then: (response) => { - console.log("API Response:", response); // Debugging + } + ) + .then((response) => response.json()) + .then((data) => { + if (!data || !Array.isArray(data.data)) { + console.error("Error: Data is not an array", data); + return; + } - if (!response.data || !Array.isArray(response.data)) { - console.error( - "Error: Data is not an array", - response.data - ); - return []; - } + let formattedData = data.data.map((item) => [ + this.formatCategory(item.category ?? "Unknown"), + addThousandSeparators(Number(item.nominal).toString() || 0), + moment(item.created_at).isValid() + ? moment(item.created_at).format("YYYY-MM-DD H:mm:ss") + : "-", + ]); - return response.data.map((item) => [ - this.formatCategory(item.category ?? "Unknown"), // Ensure category is not null - addThousandSeparators( - Number(item.nominal).toString() || 0 - ), // Ensure nominal is a valid number - moment(item.created_at).isValid() - ? moment(item.created_at).format( - "YYYY-MM-DD H:mm:ss" - ) - : "-", // Handle invalid dates - ]); - }, - total: (response) => response.pagination?.total || 0, - }, - width: "auto", - fixedHeader: true, - }).render(tableContainer); + // 🔥 If the table already exists, update it instead of re-creating + if (this.table) { + this.table + .updateConfig({ + data: formattedData.length > 0 ? formattedData : [], + }) + .forceRender(); + } else { + // 🔹 First-time initialization + this.table = new Grid({ + columns: [ + { name: "Kategori", data: (row) => row[0] }, + { name: "Nominal", data: (row) => row[1] }, + { + name: "Created", + data: (row) => row[2], + attributes: { + style: "width: 200px; white-space: nowrap;", + }, + }, + ], + pagination: { + limit: 50, + }, + sort: true, + data: formattedData.length > 0 ? formattedData : [], + width: "auto", + fixedHeader: true, + }).render(tableContainer); + } + }) + .catch((error) => console.error("Error fetching data:", error)); + } + + async handleFilterBtn() { + const filterBtn = document.getElementById("btnFilterData"); + if (!filterBtn) { + console.error("Button not found: #btnFilterData"); + return; + } + filterBtn.addEventListener("click", async () => { + if (!this.startDate || !this.endDate) { + console.log("No date filter applied, using default data"); + } else { + console.log( + `Filtering with dates: ${this.startDate} - ${this.endDate}` + ); + } + + // Reinitialize table with updated filters + this.initTablePaymentRecaps(); + }); + } + + async handleExportToExcel() { + const button = document.getElementById("btn-export-excel"); + if (!button) { + console.error("Button not found: #btn-export-excel"); + return; + } + + button.addEventListener("click", async () => { + button.disabled = true; + let exportUrl = new URL(button.getAttribute("data-url")); + + if (this.startDate) { + exportUrl.searchParams.append("start_date", this.startDate); + } else { + console.warn("⚠️ start_date is missing"); + } + + if (this.endDate) { + exportUrl.searchParams.append("end_date", this.endDate); + } else { + console.warn("⚠️ end_date is missing"); + } + + // Final check + console.log("Final Export URL:", exportUrl.toString()); + try { + const response = await fetch(`${exportUrl}`, { + method: "GET", + credentials: "include", + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + }, + }); + if (!response.ok) { + console.error("Error fetching data:", response.statusText); + button.disabled = false; + return; + } + + // Convert response to Blob and trigger download + const blob = await response.blob(); + const url = window.URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = "rekap-pembayaran.xlsx"; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + } catch (error) { + console.error("Error fetching data:", error); + button.disabled = false; + return; + } finally { + button.disabled = false; + } + }); + } + + async handleExportPDF() { + const button = document.getElementById("btn-export-pdf"); + if (!button) { + console.error("Button not found: #btn-export-pdf"); + return; + } + + button.addEventListener("click", async () => { + button.disabled = true; + let exportUrl = new URL(button.getAttribute("data-url")); + + if (this.startDate) { + exportUrl.searchParams.append("start_date", this.startDate); + } else { + console.warn("⚠️ start_date is missing"); + } + + if (this.endDate) { + exportUrl.searchParams.append("end_date", this.endDate); + } else { + console.warn("⚠️ end_date is missing"); + } + try { + const response = await fetch(`${exportUrl}`, { + method: "GET", + credentials: "include", + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + }, + }); + if (!response.ok) { + console.error("Error fetching data:", response.statusText); + button.disabled = false; + return; + } + + // Convert response to Blob and trigger download + const blob = await response.blob(); + const url = window.URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = "rekap-pembayaran.pdf"; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + } catch (error) { + console.error("Error fetching data:", error); + button.disabled = false; + return; + } finally { + button.disabled = false; + } + }); } } document.addEventListener("DOMContentLoaded", function (e) { - new PaymentRecaps(); + new PaymentRecaps().init(); }); diff --git a/resources/views/exports/payment_recaps_report.blade.php b/resources/views/exports/payment_recaps_report.blade.php new file mode 100644 index 0000000..a14068d --- /dev/null +++ b/resources/views/exports/payment_recaps_report.blade.php @@ -0,0 +1,35 @@ + + + + + + Laporan Rekap Pembayaran + + + +

Laporan Rekap Pembayaran

+ + + + + + + + + + @foreach($data as $item) + + + + + + @endforeach + +
KategoriNominalCreated
{{ $item['category'] }}{{ $item['nominal'] }}{{ $item['created_at'] }}
+ + diff --git a/resources/views/payment-recaps/index.blade.php b/resources/views/payment-recaps/index.blade.php index 60372e7..d028032 100644 --- a/resources/views/payment-recaps/index.blade.php +++ b/resources/views/payment-recaps/index.blade.php @@ -13,6 +13,19 @@
+
+
Rekap Pembayaran
+
+ + +
+
diff --git a/routes/api.php b/routes/api.php index 62fb2ad..9e602cd 100644 --- a/routes/api.php +++ b/routes/api.php @@ -151,6 +151,8 @@ Route::group(['middleware' => 'auth:sanctum'], function (){ Route::get('/bigdata-resume', 'index')->name('api.bigdata-resume'); Route::get('/bigdata-report', 'bigdata_report')->name('api.bigdata-report'); Route::get('/payment-recaps', 'payment_recaps')->name('api.payment-recaps'); + Route::get('/payment-recaps/excel', 'export_excel_payment_recaps')->name('api.payment-recaps.excel'); + Route::get('/payment-recaps/pdf', 'export_pdf_payment_recaps')->name('api.payment-recaps.pdf'); Route::get('/report-director/excel', 'export_excel_report_director')->name('api.report-director.excel'); Route::get('/report-director/pdf', 'export_pdf_report_director')->name('api.report-director.pdf'); });