feat(bucok)!: tambah modul Bucok end-to-end + impor updateOrCreate

- Tambah routing, breadcrumbs, menu, dan views (index + detail)
- Controller: index/show, datatables (filter multi-kolom, sorting, pagination), impor Excel (transaksi + logging)
- Import: updateOrCreate by nomor_tiket, normalisasi tanggal & numerik, statistik impor
- Migrasi: semua kolom bisnis → string untuk konsistensi input Excel; nomor_tiket unique + index
- UX: DataTable dengan filter (tahun, bulan, cost center, status), tombol import, detail tiket

BREAKING CHANGE:
- Semua kolom bisnis kini bertipe string → perlu sesuaikan casts di model Bucok & filter tanggal/numerik di controller
This commit is contained in:
Daeng Deni Mardaeni
2025-08-19 11:30:19 +07:00
parent 19fb39b02f
commit 32baffe636
9 changed files with 1381 additions and 45 deletions

View File

@@ -0,0 +1,209 @@
<?php
namespace Modules\Lpj\Http\Controllers;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
use Modules\Lpj\Imports\BucokImport;
use Modules\Lpj\Models\Bucok;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
* Controller untuk mengelola data Bucok
*
* @package Modules\Lpj\Http\Controllers
*/
class BucokController extends Controller
{
public $user;
/**
* Menampilkan halaman index bucok
*
* @return \Illuminate\View\View
*/
public function index()
{
return view('lpj::bucok.index');
}
/**
* Menampilkan detail bucok
*
* @param int $id
* @return \Illuminate\View\View
*/
public function show($id)
{
$bucok = Bucok::findOrFail($id);
return view('lpj::bucok.show', compact('bucok'));
}
/**
* Data untuk datatables dengan server-side processing
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function dataForDatatables(Request $request)
{
if (is_null($this->user) || !$this->user->can('bucok.view')) {
// abort(403, 'Sorry! You are not allowed to view bucok.');
}
// Retrieve data from the database
$query = Bucok::query();
// Apply search filter if provided
if ($request->has('search') && !empty($request->get('search'))) {
$search = $request->get('search');
$query->where(function ($q) use ($search) {
$q->where('nomor_tiket', 'LIKE', "%$search%")
->orWhere('deskripsi', 'LIKE', "%$search%")
->orWhere('nomor_coa', 'LIKE', "%$search%")
->orWhere('nama_coa', 'LIKE', "%$search%")
->orWhere('cost_center', 'LIKE', "%$search%")
->orWhere('nama_sub_direktorat', 'LIKE', "%$search%")
->orWhere('nama_direktorat_cabang', 'LIKE', "%$search%")
->orWhere('penyelesaian', 'LIKE', "%$search%")
->orWhere('keterangan_gantung', 'LIKE', "%$search%");
});
}
// Apply date range filter
if ($request->has('start_date') && !empty($request->get('start_date'))) {
$query->whereDate('tanggal', '>=', $request->get('start_date'));
}
if ($request->has('end_date') && !empty($request->get('end_date'))) {
$query->whereDate('tanggal', '<=', $request->get('end_date'));
}
// Apply year filter
if ($request->has('year') && !empty($request->get('year'))) {
$query->byYear($request->get('year'));
}
// Apply month filter
if ($request->has('month') && !empty($request->get('month'))) {
$query->byMonth($request->get('month'));
}
// Apply cost center filter
if ($request->has('cost_center') && !empty($request->get('cost_center'))) {
$query->byCostCenter($request->get('cost_center'));
}
// Apply completion status filter
if ($request->has('completion_status') && $request->get('completion_status') !== '') {
$isCompleted = $request->get('completion_status') == '1';
$query->byCompletionStatus($isCompleted);
}
// Apply sorting if provided
if ($request->has('sortOrder') && !empty($request->get('sortOrder'))) {
$order = $request->get('sortOrder');
$column = $request->get('sortField', 'created_at');
$query->orderBy($column, $order);
} else {
$query->orderBy('created_at', 'desc');
}
// Get the total count of records
$totalRecords = $query->count();
// Apply pagination if provided
if ($request->has('page') && $request->has('size')) {
$page = $request->get('page');
$size = $request->get('size');
$offset = ($page - 1) * $size; // Calculate the offset
$query->skip($offset)->take($size);
}
// Get the filtered count of records
$filteredRecords = $query->count();
// Get the data for the current page with relationships
$data = $query->get();
// Transform data untuk datatables
$transformedData = $data->map(function ($item) {
return [
'id' => $item->id,
'no' => $item->no,
'tanggal' => $item->tanggal ? dateFormat($item->tanggal,true) : '-',
'bulan' => $item->bulan,
'tahun' => $item->tahun,
'nomor_tiket' => $item->nomor_tiket,
'nomor_coa' => $item->nomor_coa,
'nama_coa' => $item->nama_coa,
'deskripsi' => $item->deskripsi,
'nominal' => $item->nominal_formatted,
'penyelesaian' => $item->penyelesaian,
'umur_aging' => $item->umur_aging,
'cost_center' => $item->cost_center,
'nama_sub_direktorat' => $item->nama_sub_direktorat,
'nama_direktorat_cabang' => $item->nama_direktorat_cabang,
'tanggal_penyelesaian' => $item->tanggal_penyelesaian ? dateFormat($item->tanggal_penyelesaian,true) : '-',
'nominal_penyelesaian' => $item->nominal_penyelesaian_formatted,
'status_penyelesaian' => $item->status_penyelesaian,
'status_badge' => $item->status_badge,
'created_by' => $item->creator?->name ?? '-',
'created_at' => dateFormat($item->created_at,true)
];
});
// Calculate the page count
$pageCount = ceil($totalRecords / ($request->get('size', 10)));
// Calculate the current page number
$currentPage = $request->get('page', 1);
// Return the response data as a JSON object
return response()->json([
'draw' => $request->get('draw'),
'recordsTotal' => $totalRecords,
'recordsFiltered' => $filteredRecords,
'pageCount' => $pageCount,
'page' => $currentPage,
'totalCount' => $totalRecords,
'data' => $transformedData,
]);
}
/**
* Import data bucok dari Excel
*
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function import(Request $request)
{
$request->validate([
'file' => 'required|mimes:xlsx,xls,csv|max:10240' // Max 10MB
]);
DB::beginTransaction();
try {
Log::info('Importing Bucok data', ['user_id' => Auth::id(), 'filename' => $request->file('file')->getClientOriginalName()]);
$import = new BucokImport();
Excel::import($import, $request->file('file'));
$statistics = $import->getImportStatistics();
DB::commit();
Log::info('Bucok data imported successfully', ['user_id' => Auth::id()]);
return redirect()->back()->with('success', 'Data Bucok berhasil diimport. Total: ' . $statistics['total_processed'] . ', Created: ' . $statistics['created'] . ', Updated: ' . $statistics['updated'] . ', Skipped: ' . $statistics['skipped'] . ', Errors: ' . $statistics['errors']);
} catch (Exception $e) {
DB::rollback();
Log::error('Failed to import Bucok data', ['error' => $e->getMessage(), 'user_id' => Auth::id()]);
return redirect()->back()->with('error', 'Gagal import data: ' . $e->getMessage());
}
}
}

341
app/Imports/BucokImport.php Normal file
View File

@@ -0,0 +1,341 @@
<?php
namespace Modules\Lpj\Imports;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithStartRow;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Modules\Lpj\Models\Bucok;
use Carbon\Carbon;
use Exception;
/**
* Kelas untuk mengimpor data Excel ke tabel bucoks
* Menggunakan Laravel Excel dengan validasi dan batch processing
* Data dimulai dari baris ke-5 tanpa header
*/
class BucokImport implements ToCollection, WithStartRow, WithValidation, WithBatchInserts, WithChunkReading
{
private $importedCount = 0;
private $skippedCount = 0;
private $createdCount = 0;
private $updatedCount = 0;
private $errors = [];
/**
* Menentukan baris mulai membaca data (baris ke-5)
*
* @return int
*/
public function startRow(): int
{
return 5;
}
/**
* Memproses koleksi data dari Excel
*
* @param Collection $collection
* @return void
*/
public function collection(Collection $collection)
{
DB::beginTransaction();
try {
foreach ($collection as $rowIndex => $row) {
// Log setiap baris yang diproses
Log::info('Processing Bucok import row', [
'row_number' => $rowIndex + 5, // +5 karena mulai dari baris 5
'row_data' => $row->toArray()
]);
// Konversi row ke array dengan indeks numerik
$rowArray = $row->toArray();
// Skip baris kosong
if (empty(array_filter($rowArray))) {
continue;
}
// Validasi data baris
$mappedData = $this->mapRowToBucok($rowArray, $rowIndex + 5);
// Update atau create berdasarkan nomor_tiket
if (!empty($mappedData['nomor_tiket'])) {
// Update atau create berdasarkan nomor_tiket
$bucok = Bucok::updateOrCreate(
['nomor_tiket' => $mappedData['nomor_tiket']], // Kondisi pencarian
array_merge($mappedData, ['updated_by' => auth()->id()]) // Data yang akan diupdate/create
);
// Log dan tracking apakah data di-update atau di-create
if ($bucok->wasRecentlyCreated) {
$this->createdCount++;
Log::info('Bucok created successfully', [
'row_number' => $rowIndex + 5,
'nomor_tiket' => $mappedData['nomor_tiket'],
'action' => 'created'
]);
} else {
$this->updatedCount++;
Log::info('Bucok updated successfully', [
'row_number' => $rowIndex + 5,
'nomor_tiket' => $mappedData['nomor_tiket'],
'action' => 'updated'
]);
}
}
$this->importedCount++;
}
DB::commit();
// Log summary
Log::info('Bucok import completed', [
'imported' => $this->importedCount,
'skipped' => $this->skippedCount,
'total_errors' => count($this->errors)
]);
} catch (Exception $e) {
DB::rollback();
Log::error('Bucok import failed', ['error' => $e->getMessage()]);
throw $e;
}
}
/**
* Mapping data Excel berdasarkan indeks kolom ke struktur model Bucok
* Kolom dimulai dari indeks 0 (A=0, B=1, C=2, dst.)
*
* @param array $row
* @param int $rowNumber
* @return array
*/
private function mapRowToBucok(array $row, int $rowNumber): array
{
return [
'no' => $row[0] ?? null, // Kolom A
'tanggal' => !empty($row[1]) ? $this->parseDate($row[1]) : null, // Kolom B
'bulan' => $row[2] ?? null, // Kolom C
'tahun' => $row[3] ?? null, // Kolom D
'tanggal_penuh' => !empty($row[4]) ? $this->parseDate($row[4]) : null, // Kolom E
'nomor_categ' => $row[5] ?? null, // Kolom F
'coa_summary' => $row[6] ?? null, // Kolom G
'nomor_coa' => $row[7] ?? null, // Kolom H
'nama_coa' => $row[8] ?? null, // Kolom I
'nomor_tiket' => $row[9] ?? null, // Kolom J - Auto-generate jika kosong
'deskripsi' => $row[10] ?? null, // Kolom K
'nominal' => $this->parseNumeric($row[11] ?? 0), // Kolom L
'penyelesaian' => $row[12] ?? 'Belum Selesai', // Kolom M
'umur_aging' => $this->parseNumeric($row[13] ?? 0), // Kolom N
'cost_center' => $row[14] ?? null, // Kolom O
'nama_sub_direktorat' => $row[15] ?? null, // Kolom P
'nama_direktorat_cabang' => $row[16] ?? null, // Kolom Q
'tanggal_penyelesaian' => !empty($row[17]) ? $this->parseDate($row[17]) : null, // Kolom R
'nominal_penyelesaian' => $this->parseNumeric($row[18] ?? 0), // Kolom S
'nominal_berjalan' => $this->parseNumeric($row[19] ?? 0), // Kolom T
'amortisasi_berjalan' => $this->parseNumeric($row[20] ?? 0), // Kolom U
'sistem_berjalan' => $this->parseNumeric($row[21] ?? 0), // Kolom V
'lainnya_berjalan' => $this->parseNumeric($row[22] ?? 0), // Kolom W
'nominal_gantung' => $this->parseNumeric($row[23] ?? 0), // Kolom X
'aset_gantung' => $this->parseNumeric($row[24] ?? 0), // Kolom Y
'keterangan_gantung' => $row[25] ?? null, // Kolom Z
'lainnya_satu' => $row[26] ?? null, // Kolom AA
'lainnya_dua' => $row[27] ?? null, // Kolom AB
'created_by' => auth()->id(),
'updated_by' => auth()->id()
];
}
/**
* Parse tanggal dari berbagai format
*
* @param mixed $dateValue
* @return Carbon|null
*/
private function parseDate($dateValue)
{
if (empty($dateValue)) {
return null;
}
try {
// Jika berupa angka Excel date serial
if (is_numeric($dateValue)) {
return Carbon::createFromFormat('Y-m-d', \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($dateValue)->format('Y-m-d'));
}
// Jika berupa string tanggal
return Carbon::parse($dateValue);
} catch (Exception $e) {
Log::warning('Failed to parse date', ['value' => $dateValue, 'error' => $e->getMessage()]);
return null;
}
}
/**
* Parse nilai numerik dari berbagai format
*
* @param mixed $numericValue
* @return float
*/
private function parseNumeric($numericValue): float
{
if (empty($numericValue)) {
return 0;
}
// Hapus karakter non-numerik kecuali titik dan koma
$cleaned = preg_replace('/[^0-9.,\-]/', '', $numericValue);
// Ganti koma dengan titik untuk decimal
$cleaned = str_replace(',', '.', $cleaned);
return (float) $cleaned;
}
/**
* Validasi data yang sudah dimapping
*
* @param array $data
* @return \Illuminate\Validation\Validator
*/
private function validateMappedData(array $data)
{
return Validator::make($data, [
'no' => 'nullable|integer',
'tanggal' => 'nullable|date',
'bulan' => 'nullable|integer|between:1,12',
'tahun' => 'nullable|integer|min:2000|max:2099',
'tanggal_penuh' => 'nullable|date',
'nomor_categ' => 'nullable|string|max:50',
'coa_summary' => 'nullable|string|max:255',
'nomor_coa' => 'nullable|string|max:50',
'nama_coa' => 'nullable|string|max:255',
'nomor_tiket' => 'nullable|string|max:50',
'deskripsi' => 'nullable|string',
'nominal' => 'nullable|numeric|min:0',
'penyelesaian' => 'nullable|in:Selesai,Belum Selesai,Dalam Proses',
'umur_aging' => 'nullable|integer|min:0',
'cost_center' => 'nullable|string|max:100',
'nama_sub_direktorat' => 'nullable|string|max:255',
'nama_direktorat_cabang' => 'nullable|string|max:255',
'tanggal_penyelesaian' => 'nullable|date',
'nominal_penyelesaian' => 'nullable|numeric|min:0',
'nominal_berjalan' => 'nullable|numeric|min:0',
'amortisasi_berjalan' => 'nullable|numeric|min:0',
'sistem_berjalan' => 'nullable|numeric|min:0',
'lainnya_berjalan' => 'nullable|numeric|min:0',
'nominal_gantung' => 'nullable|numeric|min:0',
'aset_gantung' => 'nullable|numeric|min:0',
'keterangan_gantung' => 'nullable|string',
'lainnya_satu' => 'nullable|string',
'lainnya_dua' => 'nullable|string'
]);
}
/**
* Aturan validasi untuk seluruh file Excel (tidak digunakan karena tanpa header)
*
* @return array
*/
public function rules(): array
{
return [];
}
/**
* Ukuran batch untuk insert
*
* @return int
*/
public function batchSize(): int
{
return 100;
}
/**
* Ukuran chunk untuk membaca file
*
* @return int
*/
public function chunkSize(): int
{
return 100;
}
/**
* Mendapatkan jumlah data yang berhasil diimpor
*
* @return int
*/
public function getImportedCount(): int
{
return $this->importedCount;
}
/**
* Mendapatkan jumlah data yang berhasil dibuat
*
* @return int
*/
public function getCreatedCount(): int
{
return $this->createdCount;
}
/**
* Mendapatkan jumlah data yang berhasil diupdate
*
* @return int
*/
public function getUpdatedCount(): int
{
return $this->updatedCount;
}
/**
* Mendapatkan statistik lengkap import
*
* @return array
*/
public function getImportStatistics(): array
{
return [
'total_processed' => $this->importedCount,
'created' => $this->createdCount,
'updated' => $this->updatedCount,
'skipped' => $this->skippedCount,
'errors' => count($this->errors)
];
}
/**
* Mendapatkan jumlah data yang dilewati
*
* @return int
*/
public function getSkippedCount(): int
{
return $this->skippedCount;
}
/**
* Mendapatkan daftar error yang terjadi
*
* @return array
*/
public function getErrors(): array
{
return $this->errors;
}
}

113
app/Models/Bucok.php Normal file
View File

@@ -0,0 +1,113 @@
<?php
namespace Modules\Lpj\Models;
use Illuminate\Foundation\Auth\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Str;
/**
* Model Bucok untuk mengelola data bucok
*
* @property int $id
* @property int|null $no
* @property string|null $tanggal
* @property string|null $bulan
* @property int|null $tahun
* @property string|null $tanggal_penuh
* @property string|null $nomor_categ
* @property string|null $coa_summary
* @property string|null $nomor_coa
* @property string|null $nama_coa
* @property string $nomor_tiket
* @property string|null $deskripsi
* @property float|null $nominal
* @property string|null $penyelesaian
* @property int|null $umur_aging
* @property string|null $cost_center
* @property string|null $nama_sub_direktorat
* @property string|null $nama_direktorat_cabang
* @property string|null $tanggal_penyelesaian
* @property float|null $nominal_penyelesaian
* @property float|null $nominal_berjalan
* @property float|null $amortisasi_berjalan
* @property float|null $sistem_berjalan
* @property float|null $lainnya_berjalan
* @property float|null $nominal_gantung
* @property float|null $aset_gantung
* @property string|null $keterangan_gantung
* @property string|null $lainnya_satu
* @property string|null $lainnya_dua
*/
class Bucok extends Base
{
use HasFactory;
/**
* Nama tabel yang digunakan oleh model
*/
protected $table = 'bucoks';
/**
* Field yang dapat diisi secara mass assignment
*/
protected $fillable = [
'no',
'tanggal',
'bulan',
'tahun',
'tanggal_penuh',
'nomor_categ',
'coa_summary',
'nomor_coa',
'nama_coa',
'nomor_tiket',
'deskripsi',
'nominal',
'penyelesaian',
'umur_aging',
'cost_center',
'nama_sub_direktorat',
'nama_direktorat_cabang',
'tanggal_penyelesaian',
'nominal_penyelesaian',
'nominal_berjalan',
'amortisasi_berjalan',
'sistem_berjalan',
'lainnya_berjalan',
'nominal_gantung',
'aset_gantung',
'keterangan_gantung',
'lainnya_satu',
'lainnya_dua',
];
/**
* Casting tipe data untuk field tertentu
*/
protected $casts = [
'no' => 'integer',
'tanggal' => 'date',
'tahun' => 'integer',
'tanggal_penuh' => 'date',
'nominal' => 'decimal:2',
'umur_aging' => 'integer',
'tanggal_penyelesaian' => 'date',
'nominal_penyelesaian' => 'decimal:2',
'nominal_berjalan' => 'decimal:2',
'amortisasi_berjalan' => 'decimal:2',
'sistem_berjalan' => 'decimal:2',
'lainnya_berjalan' => 'decimal:2',
'nominal_gantung' => 'decimal:2',
'aset_gantung' => 'decimal:2',
];
/**
* Field yang akan di-hidden saat serialization
*/
protected $hidden = [
'created_by',
'updated_by',
'deleted_by',
];
}

View File

@@ -0,0 +1,67 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('bucoks', function (Blueprint $table) {
$table->id();
$table->string('no')->nullable(); // Nomor urut
$table->string('tanggal')->nullable(); // Tanggal
$table->string('bulan')->nullable(); // Bulan
$table->string('tahun')->nullable(); // Tahun
$table->string('tanggal_penuh')->nullable(); // Tanggal lengkap
$table->string('nomor_categ')->nullable(); // Nomor kategori
$table->string('coa_summary')->nullable(); // COA Summary
$table->string('nomor_coa')->nullable(); // Nomor COA
$table->string('nama_coa')->nullable(); // Nama COA
$table->string('nomor_tiket')->unique(); // Nomor tiket (unique)
$table->string('deskripsi')->nullable(); // Deskripsi
$table->string('nominal')->nullable(); // Nominal
$table->string('penyelesaian')->nullable(); // Penyelesaian
$table->string('umur_aging')->nullable(); // Umur aging
$table->string('cost_center')->nullable(); // Cost center
$table->string('nama_sub_direktorat')->nullable(); // Nama sub direktorat
$table->string('nama_direktorat_cabang')->nullable(); // Nama direktorat cabang
$table->string('tanggal_penyelesaian')->nullable(); // Tanggal penyelesaian
$table->string('nominal_penyelesaian')->nullable(); // Nominal penyelesaian
$table->string('nominal_berjalan')->nullable(); // Nominal berjalan
$table->string('amortisasi_berjalan')->nullable(); // Amortisasi berjalan
$table->string('sistem_berjalan')->nullable(); // Sistem berjalan
$table->string('lainnya_berjalan')->nullable(); // Lainnya berjalan
$table->string('nominal_gantung')->nullable(); // Nominal gantung
$table->string('aset_gantung')->nullable(); // Aset gantung
$table->string('keterangan_gantung')->nullable(); // Keterangan gantung
$table->string('lainnya_satu')->nullable(); // Lainnya satu
$table->string('lainnya_dua')->nullable(); // Lainnya dua
// Standard Laravel fields
$table->timestamps();
$table->string('created_by')->nullable();
$table->string('updated_by')->nullable();
$table->string('deleted_by')->nullable();
$table->softDeletes();
// Indexes untuk performa
$table->index(['nomor_tiket']);
$table->index(['tanggal']);
$table->index(['tahun']);
$table->index(['nomor_coa']);
$table->index(['cost_center']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('bucoks');
}
};

View File

@@ -413,6 +413,18 @@
"administrator",
"noc"
]
},
{
"title": "Bucok",
"path": "bucok",
"icon": "ki-filled ki-two-credit-cart text-lg text-primary",
"classes": "",
"attributes": [],
"permission": "",
"roles": [
"administrator",
"noc"
]
}
]
},

View File

@@ -0,0 +1,342 @@
@extends('layouts.main')
@section('breadcrumbs')
{{ Breadcrumbs::render('bucok') }}
@endsection
@section('content')
<div class="grid">
<div class="min-w-full border card border-agi-100 card-grid" data-datatable="false" data-datatable-page-size="10" data-datatable-state-save="false" id="bucok-table" data-api-url="{{ route('bucok.datatables') }}">
<div class="flex-wrap py-5 card-header bg-agi-50">
<h3 class="card-title">
Data Bucok
</h3>
<div class="flex flex-wrap gap-2 lg:gap-5">
<div class="flex">
<label class="input input-sm">
<i class="ki-filled ki-magnifier"></i>
<input placeholder="Search Bucok" id="search" type="text" value="">
</label>
</div>
<div class="flex flex-wrap gap-2.5">
<div class="h-[24px] border border-r-gray-200"></div>
<!-- Filter Tahun -->
<select class="select select-sm" id="year-filter">
<option value="">Semua Tahun</option>
@for($year = date('Y'); $year >= 2020; $year--)
<option value="{{ $year }}">{{ $year }}</option>
@endfor
</select>
<!-- Filter Bulan -->
<select class="select select-sm" id="month-filter">
<option value="">Semua Bulan</option>
@for($month = 1; $month <= 12; $month++)
<option value="{{ $month }}">{{ DateTime::createFromFormat('!m', $month)->format('F') }}</option>
@endfor
</select>
<!-- Filter Status Penyelesaian -->
<select class="select select-sm" id="completion-status-filter">
<option value="">Semua Status</option>
<option value="1">Selesai</option>
<option value="0">Belum Selesai</option>
</select>
<!-- Import Excel -->
<button class="btn btn-sm btn-success" data-modal-toggle="#import-modal">
<i class="ki-filled ki-file-up"></i> Import Excel
</button>
<a class="btn btn-sm btn-light" href="#" id="export-excel">
<i class="ki-filled ki-file-down"></i> Export Excel
</a>
</div>
</div>
</div>
<div class="card-body">
<div class="scrollable-x-auto">
<table class="table text-sm font-medium text-gray-700 align-middle table-auto table-border" data-datatable-table="true">
<thead>
<tr>
<th class="w-14">
<input class="checkbox checkbox-sm" data-datatable-check="true" type="checkbox"/>
</th>
<th class="min-w-[80px]" data-datatable-column="no">
<span class="sort">
<span class="sort-label">No</span>
<span class="sort-icon"></span>
</span>
</th>
<th class="min-w-[100px]" data-datatable-column="tanggal">
<span class="sort">
<span class="sort-label">Tanggal</span>
<span class="sort-icon"></span>
</span>
</th>
<th class="min-w-[120px]" data-datatable-column="nomor_tiket">
<span class="sort">
<span class="sort-label">Nomor Tiket</span>
<span class="sort-icon"></span>
</span>
</th>
<th class="min-w-[100px]" data-datatable-column="nomor_coa">
<span class="sort">
<span class="sort-label">Nomor COA</span>
<span class="sort-icon"></span>
</span>
</th>
<th class="min-w-[150px]" data-datatable-column="nama_coa">
<span class="sort">
<span class="sort-label">Nama COA</span>
<span class="sort-icon"></span>
</span>
</th>
<th class="min-w-[200px]" data-datatable-column="deskripsi">
<span class="sort">
<span class="sort-label">Deskripsi</span>
<span class="sort-icon"></span>
</span>
</th>
<th class="min-w-[120px]" data-datatable-column="nominal">
<span class="sort">
<span class="sort-label">Nominal</span>
<span class="sort-icon"></span>
</span>
</th>
<th class="min-w-[100px]" data-datatable-column="cost_center">
<span class="sort">
<span class="sort-label">Cost Center</span>
<span class="sort-icon"></span>
</span>
</th>
<th class="min-w-[100px]" data-datatable-column="status_penyelesaian">
<span class="sort">
<span class="sort-label">Status</span>
<span class="sort-icon"></span>
</span>
</th>
<th class="min-w-[50px] text-center" data-datatable-column="actions">Aksi</th>
</tr>
</thead>
</table>
</div>
<div class="flex-col gap-3 justify-center font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
<div class="flex gap-2 items-center">
Show
<select class="w-16 select select-sm" data-datatable-size="true" name="perpage"> </select> per page
</div>
<div class="flex gap-4 items-center">
<span data-datatable-info="true"> </span>
<div class="pagination" data-datatable-pagination="true">
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Modal Import Excel -->
<div class="modal" data-modal="true" id="import-modal">
<div class="modal-content max-w-[500px] top-[15%]">
<div class="modal-header">
<h3 class="modal-title">Import Data Bucok</h3>
<button class="btn btn-sm btn-icon btn-light btn-clear shrink-0" data-modal-dismiss="true">
<i class="ki-filled ki-cross"></i>
</button>
</div>
<form action="{{ route('bucok.import') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="modal-body">
<div class="flex flex-col gap-5">
<div class="flex flex-col gap-2.5">
<label class="text-gray-900 form-label">File Excel</label>
<input type="file" name="file" class="file-input" accept=".xlsx,.xls,.csv" required>
<div class="text-gray-600 text-2sm">
Format yang didukung: .xlsx, .xls, .csv (Maksimal 10MB)
</div>
</div>
<div class="p-3 bg-yellow-100 rounded border border-yellow-300">
<div class="text-sm text-yellow-800">
<strong>Catatan:</strong>
<ul class="mt-1 list-disc list-inside">
<li>Data akan dimulai dari baris ke-5</li>
<li>File Excel tidak perlu header</li>
<li>Data akan di-update jika nomor tiket sudah ada</li>
</ul>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<div class="flex gap-4">
<button type="button" class="btn btn-light" data-modal-dismiss="true">Batal</button>
<button type="submit" class="btn btn-primary">Import</button>
</div>
</div>
</form>
</div>
</div>
@endsection
@push('scripts')
<script>
/**
* Fungsi untuk menghapus data Bucok
* @param {number} data - ID data yang akan dihapus
*/
function deleteData(data) {
Swal.fire({
title: 'Apakah Anda yakin?',
text: "Data yang dihapus tidak dapat dikembalikan!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Ya, hapus!',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
});
$.ajax(`bucok/${data}`, {
type: 'DELETE'
}).then((response) => {
Swal.fire('Terhapus!', 'Data Bucok berhasil dihapus.', 'success').then(() => {
window.location.reload();
});
}).catch((error) => {
Swal.fire('Error!', error.responseJSON.message, 'error');
});
}
})
}
</script>
<script type="module">
/**
* Inisialisasi DataTable untuk Bucok menggunakan KTDataTable
*/
document.addEventListener('DOMContentLoaded', function() {
const element = document.querySelector('#bucok-table');
const searchInput = document.getElementById('search');
const yearFilter = document.getElementById('year-filter');
const monthFilter = document.getElementById('month-filter');
const completionStatusFilter = document.getElementById('completion-status-filter');
const apiUrl = element.getAttribute('data-api-url');
// Konfigurasi DataTable menggunakan KTDataTable
const dataTableOptions = {
apiEndpoint: apiUrl,
pageSize: 10,
columns: {
select: {
render: (item, data, context) => {
const checkbox = document.createElement('input');
checkbox.className = 'checkbox checkbox-sm';
checkbox.type = 'checkbox';
checkbox.value = data.id.toString();
checkbox.setAttribute('data-datatable-row-check', 'true');
return checkbox.outerHTML.trim();
},
},
no: {
title: 'No',
},
tanggal: {
title: 'Tanggal',
},
nomor_tiket: {
title: 'Nomor Tiket',
},
nomor_coa: {
title: 'Nomor COA',
},
nama_coa: {
title: 'Nama COA',
},
deskripsi: {
title: 'Deskripsi',
render: (item, data) => {
const desc = data.deskripsi || '-';
return desc.length > 50 ? desc.substring(0, 50) + '...' : desc;
},
},
nominal: {
title: 'Nominal',
},
cost_center: {
title: 'Cost Center',
},
status_badge: {
title: 'Status',
render: (item, data) => {
return data.status_badge || '-';
},
},
actions: {
title: 'Aksi',
render: (item, data) => {
return data.actions || '';
},
}
},
};
// Inisialisasi DataTable
let dataTable = new KTDataTable(element, dataTableOptions);
dataTable.showSpinner();
// Fungsi pencarian
searchInput.addEventListener('input', function () {
const searchValue = this.value.trim();
dataTable.search(searchValue, true);
});
// Filter berdasarkan tahun
yearFilter.addEventListener('change', function() {
const yearValue = this.value;
// Implementasi filter tahun - perlu disesuaikan dengan API endpoint
dataTable.setParam('year', yearValue);
dataTable.reload();
});
// Filter berdasarkan bulan
monthFilter.addEventListener('change', function() {
const monthValue = this.value;
// Implementasi filter bulan - perlu disesuaikan dengan API endpoint
dataTable.setParam('month', monthValue);
dataTable.reload();
});
// Filter berdasarkan status penyelesaian
completionStatusFilter.addEventListener('change', function() {
const statusValue = this.value;
// Implementasi filter status - perlu disesuaikan dengan API endpoint
dataTable.setParam('completion_status', statusValue);
dataTable.reload();
});
// Export Excel functionality
document.getElementById('export-excel').addEventListener('click', function(e) {
e.preventDefault();
// Build export URL with current filters
const params = new URLSearchParams();
if (searchInput.value) params.append('search', searchInput.value);
if (yearFilter.value) params.append('year', yearFilter.value);
if (monthFilter.value) params.append('month', monthFilter.value);
if (completionStatusFilter.value) params.append('completion_status', completionStatusFilter.value);
const exportUrl = '{{ route("bucok.export") }}?' + params.toString();
window.open(exportUrl, '_blank');
});
});
</script>
@endpush

View File

@@ -0,0 +1,236 @@
@extends('layouts.main')
@section('breadcrumbs')
{{ Breadcrumbs::render('bucok.show', $bucok) }}
@endsection
@section('content')
<div class="grid gap-5 lg:gap-7.5">
<!-- Header Card -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Detail Bucok #{{ $bucok->nomor_tiket }}</h3>
<div class="flex gap-2">
<a href="{{ route('bucok.index') }}" class="btn btn-sm btn-light">
<i class="ki-filled ki-left"></i> Kembali
</a>
</div>
</div>
</div>
<!-- Detail Information -->
<div class="grid gap-5 lg:grid-cols-2 lg:gap-7.5">
<!-- Informasi Dasar -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Informasi Dasar</h3>
</div>
<div class="card-body">
<div class="grid gap-5">
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">No</div>
<div class="text-gray-700 text-2sm">{{ $bucok->no ?? '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Tanggal</div>
<div class="text-gray-700 text-2sm">
{{ $bucok->tanggal ? dateFormat($bucok->tanggal, true) : '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Bulan</div>
<div class="text-gray-700 text-2sm">{{ $bucok->bulan ?? '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Tahun</div>
<div class="text-gray-700 text-2sm">{{ $bucok->tahun ?? '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Nomor Tiket</div>
<div class="font-medium text-gray-700 text-2sm">{{ $bucok->nomor_tiket }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Status Penyelesaian</div>
<div class="text-2sm">{!! $bucok->status_badge !!}</div>
</div>
</div>
</div>
</div>
</div>
<!-- Informasi COA -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Informasi COA</h3>
</div>
<div class="card-body">
<div class="grid gap-5">
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Nomor COA</div>
<div class="text-gray-700 text-2sm">{{ $bucok->nomor_coa ?? '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Nama COA</div>
<div class="text-gray-700 text-2sm">{{ $bucok->nama_coa ?? '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Deskripsi</div>
<div class="text-gray-700 text-2sm">{{ $bucok->deskripsi ?? '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Nominal</div>
<div class="font-medium text-gray-700 text-2sm">{{ $bucok->nominal_formatted }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Informasi Organisasi -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Informasi Organisasi</h3>
</div>
<div class="card-body">
<div class="grid gap-5 lg:grid-cols-3">
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Cost Center</div>
<div class="text-gray-700 text-2sm">{{ $bucok->cost_center ?? '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Sub Direktorat</div>
<div class="text-gray-700 text-2sm">{{ $bucok->nama_sub_direktorat ?? '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Direktorat/Cabang</div>
<div class="text-gray-700 text-2sm">{{ $bucok->nama_direktorat_cabang ?? '-' }}</div>
</div>
</div>
</div>
</div>
</div>
<!-- Informasi Penyelesaian -->
@if ($bucok->tanggal_penyelesaian || $bucok->nominal_penyelesaian || $bucok->penyelesaian)
<div class="card">
<div class="card-header">
<h3 class="card-title">Informasi Penyelesaian</h3>
</div>
<div class="card-body">
<div class="grid gap-5 lg:grid-cols-2">
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Tanggal Penyelesaian</div>
<div class="text-gray-700 text-2sm">
{{ $bucok->tanggal_penyelesaian ? dateFormat($bucok->tanggal_penyelesaian, true) : '-' }}
</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Nominal Penyelesaian</div>
<div class="font-medium text-gray-700 text-2sm">
{{ $bucok->nominal_penyelesaian_formatted }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Penyelesaian</div>
<div class="text-gray-700 text-2sm">{{ $bucok->penyelesaian ?? '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Umur Aging</div>
<div class="text-gray-700 text-2sm">{{ $bucok->umur_aging ?? '-' }} hari</div>
</div>
</div>
@if ($bucok->keterangan_gantung)
<div class="flex justify-between items-center py-2.5">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Keterangan Gantung</div>
<div class="text-gray-700 text-2sm">{{ $bucok->keterangan_gantung }}</div>
</div>
</div>
@endif
</div>
</div>
</div>
@endif
<!-- Informasi Audit -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Informasi Audit</h3>
</div>
<div class="card-body">
<div class="grid gap-5 lg:grid-cols-2">
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Dibuat Oleh</div>
<div class="text-gray-700 text-2sm">{{ $bucok->creator?->name ?? '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Tanggal Dibuat</div>
<div class="text-gray-700 text-2sm">{{ dateFormat($bucok->created_at, true) }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5 border-b border-gray-200">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Diperbarui Oleh</div>
<div class="text-gray-700 text-2sm">{{ $bucok->updater?->name ?? '-' }}</div>
</div>
</div>
<div class="flex justify-between items-center py-2.5">
<div class="flex flex-col gap-1">
<div class="text-sm font-medium text-gray-900">Tanggal Diperbarui</div>
<div class="text-gray-700 text-2sm">{{ dateFormat($bucok->updated_at, true) }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -806,7 +806,15 @@ Breadcrumbs::for('memo.preview', function (BreadcrumbTrail $trail) {
$trail->push('Preview', route('memo.index'));
});
// Breadcrumb untuk Bucok
Breadcrumbs::for('bucok', function (BreadcrumbTrail $trail) {
$trail->push('Data Bucok', route('bucok.index'));
});
Breadcrumbs::for('bucok.show', function (BreadcrumbTrail $trail, $bucok) {
$trail->parent('bucok');
$trail->push('Detail Bucok #' . $bucok->nomor_tiket);
});
// add andy
require __DIR__ . '/breadcrumbs_registrasi.php';

View File

@@ -1,58 +1,59 @@
<?php
use Illuminate\Support\Facades\Route;
use Modules\Lpj\Http\Controllers\ActivityController;
use Modules\Lpj\Http\Controllers\ArahMataAnginController;
use Modules\Lpj\Http\Controllers\BankDataController;
use Modules\Lpj\Http\Controllers\CustomFieldController;
use Modules\Lpj\Http\Controllers\DebitureController;
use Modules\Lpj\Http\Controllers\DokumenJaminanController;
use Modules\Lpj\Http\Controllers\HubunganPemilikJaminanController;
use Modules\Lpj\Http\Controllers\HubunganPenghuniJaminanController;
use Modules\Lpj\Http\Controllers\IjinUsahaController;
use Modules\Lpj\Http\Controllers\JenisDokumenController;
use Modules\Lpj\Http\Controllers\JenisFasilitasKreditController;
use Modules\Lpj\Http\Controllers\JenisJaminanController;
use Modules\Lpj\Http\Controllers\JenisLampiranController;
use Modules\Lpj\Http\Controllers\JenisLaporanController;
use Modules\Lpj\Http\Controllers\JenisLegalitasJaminanController;
use Modules\Lpj\Http\Controllers\JenisPenilaianController;
use Modules\Lpj\Http\Controllers\KJPPController;
use Modules\Lpj\Http\Controllers\LampiranDokumenController;
use Modules\Lpj\Http\Controllers\LaporanAdminKreditController;
use Modules\Lpj\Http\Controllers\LaporanController;
use Modules\Lpj\Http\Controllers\LaporanExternalController;
use Modules\Lpj\Http\Controllers\LaporanHasilPenilaianJaminanInternalExternalController;
use Modules\Lpj\Http\Controllers\LaporanPembatalanController;
use Modules\Lpj\Http\Controllers\LaporanPenilaianJaminanController;
use Modules\Lpj\Http\Controllers\LaporanPermohonanController;
use Modules\Lpj\Http\Controllers\NilaiPlafondController;
use Modules\Lpj\Http\Controllers\NocController;
use Modules\Lpj\Http\Controllers\PembatalanController;
use Modules\Lpj\Http\Controllers\PemilikJaminanController;
use Modules\Lpj\Http\Controllers\PenilaianController;
use Modules\Lpj\Http\Controllers\PenilaiController;
use Modules\Lpj\Http\Controllers\PermohonanController;
use Modules\Lpj\Http\Controllers\PersetujuanPenawaranController;
use Modules\Lpj\Http\Controllers\SLAController;
use Modules\Lpj\Http\Controllers\KJPPController;
use Modules\Lpj\Http\Controllers\MemoController;
use Modules\Lpj\Http\Controllers\BucokController;
use Modules\Lpj\Http\Controllers\TeamsController;
use Modules\Lpj\Http\Controllers\RegionController;
use Modules\Lpj\Http\Controllers\ResumeController;
use Modules\Lpj\Http\Controllers\SLAController;
use Modules\Lpj\Http\Controllers\StatusPermohonanController;
use Modules\Lpj\Http\Controllers\SurveyorController;
use Modules\Lpj\Http\Controllers\TeamsController;
use Modules\Lpj\Http\Controllers\TenderController;
use Modules\Lpj\Http\Controllers\TujuanPenilaianController;
use Modules\Lpj\Http\Controllers\TujuanPenilaianKJPPController;
use Modules\Lpj\Http\Controllers\LaporanPenilaiJaminanController;
use Modules\Lpj\Http\Controllers\RekapHarianSoController;
use Modules\Lpj\Http\Controllers\LaporanBiayaInternalExternalController;
use Modules\Lpj\Http\Controllers\LaporanMonitoringSoController;
use Modules\Lpj\Http\Controllers\LaporanDebitureController;
use Modules\Lpj\Http\Controllers\LaporanController;
use Modules\Lpj\Http\Controllers\PenilaiController;
use Modules\Lpj\Http\Controllers\ActivityController;
use Modules\Lpj\Http\Controllers\BankDataController;
use Modules\Lpj\Http\Controllers\DebitureController;
use Modules\Lpj\Http\Controllers\SurveyorController;
use Modules\Lpj\Http\Controllers\IjinUsahaController;
use Modules\Lpj\Http\Controllers\PenilaianController;
use Modules\Lpj\Http\Controllers\PembatalanController;
use Modules\Lpj\Http\Controllers\PermohonanController;
use Modules\Lpj\Http\Controllers\CustomFieldController;
use Modules\Lpj\Http\Controllers\LaporanUserController;
use Modules\Lpj\Http\Controllers\LaporanSLAPenilaiController;
use Modules\Lpj\Http\Controllers\JenisDokumenController;
use Modules\Lpj\Http\Controllers\JenisJaminanController;
use Modules\Lpj\Http\Controllers\JenisLaporanController;
use Modules\Lpj\Http\Controllers\NilaiPlafondController;
use Modules\Lpj\Http\Controllers\ArahMataAnginController;
use Modules\Lpj\Http\Controllers\DaftarPustakaController;
use Modules\Lpj\Http\Controllers\JenisLampiranController;
use Modules\Lpj\Http\Controllers\RekapHarianSoController;
use Modules\Lpj\Http\Controllers\DokumenJaminanController;
use Modules\Lpj\Http\Controllers\JenisPenilaianController;
use Modules\Lpj\Http\Controllers\PemilikJaminanController;
use Modules\Lpj\Http\Controllers\LampiranDokumenController;
use Modules\Lpj\Http\Controllers\LaporanDebitureController;
use Modules\Lpj\Http\Controllers\LaporanExternalController;
use Modules\Lpj\Http\Controllers\TujuanPenilaianController;
use Modules\Lpj\Http\Controllers\StatusPermohonanController;
use Modules\Lpj\Http\Controllers\LaporanPembatalanController;
use Modules\Lpj\Http\Controllers\LaporanPermohonanController;
use Modules\Lpj\Http\Controllers\LaporanSLAPenilaiController;
use Modules\Lpj\Http\Controllers\LaporanAdminKreditController;
use Modules\Lpj\Http\Controllers\LaporanMonitoringSoController;
use Modules\Lpj\Http\Controllers\TujuanPenilaianKJPPController;
use Modules\Lpj\Http\Controllers\JenisFasilitasKreditController;
use Modules\Lpj\Http\Controllers\PersetujuanPenawaranController;
use Modules\Lpj\Http\Controllers\CategoryDaftarPustakaController;
use Modules\Lpj\Http\Controllers\MemoController;
use Modules\Lpj\Http\Controllers\JenisLegalitasJaminanController;
use Modules\Lpj\Http\Controllers\LaporanPenilaiJaminanController;
use Modules\Lpj\Http\Controllers\HubunganPemilikJaminanController;
use Modules\Lpj\Http\Controllers\HubunganPenghuniJaminanController;
use Modules\Lpj\Http\Controllers\LaporanPenilaianJaminanController;
use Modules\Lpj\Http\Controllers\LaporanBiayaInternalExternalController;
use Modules\Lpj\Http\Controllers\LaporanHasilPenilaianJaminanInternalExternalController;
@@ -792,6 +793,13 @@ Route::middleware(['auth'])->group(function () {
Route::resource('category-daftar-pustaka', CategoryDaftarPustakaController::class);
// Route untuk Bucok
Route::prefix('bucok')->name('bucok.')->group(function () {
Route::get('/', [BucokController::class, 'index'])->name('index');
Route::get('/datatables', [BucokController::class, 'dataForDatatables'])->name('datatables');
Route::get('/{id}', [BucokController::class, 'show'])->name('show');
Route::post('/import', [BucokController::class, 'import'])->name('import');
});
});
require __DIR__ . '/registrasi.php';