✨ 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:
209
app/Http/Controllers/BucokController.php
Normal file
209
app/Http/Controllers/BucokController.php
Normal 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
341
app/Imports/BucokImport.php
Normal 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
113
app/Models/Bucok.php
Normal 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',
|
||||
];
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
};
|
||||
12
module.json
12
module.json
@@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
342
resources/views/bucok/index.blade.php
Normal file
342
resources/views/bucok/index.blade.php
Normal 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
|
||||
236
resources/views/bucok/show.blade.php
Normal file
236
resources/views/bucok/show.blade.php
Normal 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
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user