update tgl 7 mei2

This commit is contained in:
whywdd 2025-05-07 05:43:55 +07:00
parent a2c3a61a32
commit 0be2b98301
8 changed files with 972 additions and 258 deletions

View File

@ -5,6 +5,11 @@
use App\Models\NeracasaldoModel; use App\Models\NeracasaldoModel;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Carbon\Carbon; use Carbon\Carbon;
use Maatwebsite\Excel\Facades\Excel;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Barryvdh\DomPDF\Facade\Pdf;
use App\Exports\NeracaSaldoExport;
class NeracasaldoController extends Controller class NeracasaldoController extends Controller
{ {
@ -144,4 +149,275 @@ public function show($id)
$transaksi = NeracasaldoModel::findOrFail($id); $transaksi = NeracasaldoModel::findOrFail($id);
return view('neracasaldo.show', compact('transaksi')); return view('neracasaldo.show', compact('transaksi'));
} }
public function exportExcel(Request $request)
{
try {
// Ambil parameter filter tanggal jika ada
$startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d'));
$endDate = $request->input('end_date', Carbon::now()->endOfMonth()->format('Y-m-d'));
$rawTransaksis = NeracasaldoModel::whereBetween('Tanggal', [$startDate, $endDate])
->orderBy('kode', 'asc')
->get();
$processedData = [];
$totalsPerAkun = [];
$totalDebit = 0;
$totalKredit = 0;
// Proses data seperti di fungsi index
foreach ($rawTransaksis as $transaksi) {
$processAkun = function($kode, $kategori, $debit, $kredit) use (&$totalsPerAkun) {
if (!empty($kode) && !empty($kategori)) {
if (!isset($totalsPerAkun[$kategori])) {
$totalsPerAkun[$kategori] = [
'kode' => $kode,
'kategori' => $kategori,
'debit' => 0,
'kredit' => 0
];
}
$totalsPerAkun[$kategori]['debit'] += floatval($debit ?? 0);
$totalsPerAkun[$kategori]['kredit'] += floatval($kredit ?? 0);
}
};
$processAkun($transaksi->kode, $transaksi->kategori, $transaksi->uang_masuk, $transaksi->uang_keluar);
$processAkun($transaksi->kode2, $transaksi->kategori2, $transaksi->uang_masuk2, $transaksi->uang_keluar2);
$processAkun($transaksi->kode3, $transaksi->kategori3, $transaksi->uang_masuk3, $transaksi->uang_keluar3);
$processAkun($transaksi->kode4, $transaksi->kategori4, $transaksi->uang_masuk4, $transaksi->uang_keluar4);
$processAkun($transaksi->kode5, $transaksi->kategori5, $transaksi->uang_masuk5, $transaksi->uang_keluar5);
}
foreach ($totalsPerAkun as $kategori => $data) {
$kodeAwal = substr($data['kode'], 0, 3);
$saldo = $data['debit'] - $data['kredit'];
if (in_array($kodeAwal, ['111', '112']) || in_array($kodeAwal, ['251', '252'])) {
if ($saldo != 0) {
$processedData[] = [
'kode' => $data['kode'],
'kategori' => $kategori,
'debit' => $saldo > 0 ? abs($saldo) : 0,
'kredit' => $saldo < 0 ? abs($saldo) : 0
];
$totalDebit += $saldo > 0 ? abs($saldo) : 0;
$totalKredit += $saldo < 0 ? abs($saldo) : 0;
}
} else {
if ($saldo != 0) {
$processedData[] = [
'kode' => $data['kode'],
'kategori' => $kategori,
'debit' => $saldo < 0 ? abs($saldo) : 0,
'kredit' => $saldo > 0 ? abs($saldo) : 0
];
$totalDebit += $saldo < 0 ? abs($saldo) : 0;
$totalKredit += $saldo > 0 ? abs($saldo) : 0;
}
}
}
// Tambahkan baris total
$processedData[] = [
'kode' => '',
'kategori' => 'Total',
'debit' => $totalDebit,
'kredit' => $totalKredit
];
// Buat class export inline
$export = new class($processedData) implements FromCollection, WithHeadings {
protected $data;
public function __construct($data)
{
$this->data = collect($data);
}
public function collection()
{
return $this->data;
}
public function headings(): array
{
return [
'Kode',
'Nama Akun',
'Debit',
'Kredit'
];
}
};
return Excel::download($export, 'neraca-saldo-'.date('Y-m-d').'.xlsx');
} catch (\Exception $e) {
return redirect()->back()->with('error', 'Gagal mengekspor Excel: ' . $e->getMessage());
}
}
public function exportPDF(Request $request)
{
try {
// Ambil parameter filter tanggal jika ada
$startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d'));
$endDate = $request->input('end_date', Carbon::now()->endOfMonth()->format('Y-m-d'));
$rawTransaksis = NeracasaldoModel::whereBetween('Tanggal', [$startDate, $endDate])
->orderBy('kode', 'asc')
->get();
$processedData = [];
$totalsPerAkun = [];
$totalDebit = 0;
$totalKredit = 0;
// Proses data seperti di fungsi index
foreach ($rawTransaksis as $transaksi) {
$processAkun = function($kode, $kategori, $debit, $kredit) use (&$totalsPerAkun) {
if (!empty($kode) && !empty($kategori)) {
if (!isset($totalsPerAkun[$kategori])) {
$totalsPerAkun[$kategori] = [
'kode' => $kode,
'kategori' => $kategori,
'debit' => 0,
'kredit' => 0
];
}
$totalsPerAkun[$kategori]['debit'] += floatval($debit ?? 0);
$totalsPerAkun[$kategori]['kredit'] += floatval($kredit ?? 0);
}
};
$processAkun($transaksi->kode, $transaksi->kategori, $transaksi->uang_masuk, $transaksi->uang_keluar);
$processAkun($transaksi->kode2, $transaksi->kategori2, $transaksi->uang_masuk2, $transaksi->uang_keluar2);
$processAkun($transaksi->kode3, $transaksi->kategori3, $transaksi->uang_masuk3, $transaksi->uang_keluar3);
$processAkun($transaksi->kode4, $transaksi->kategori4, $transaksi->uang_masuk4, $transaksi->uang_keluar4);
$processAkun($transaksi->kode5, $transaksi->kategori5, $transaksi->uang_masuk5, $transaksi->uang_keluar5);
}
foreach ($totalsPerAkun as $kategori => $data) {
$kodeAwal = substr($data['kode'], 0, 3);
$saldo = $data['debit'] - $data['kredit'];
if (in_array($kodeAwal, ['111', '112']) || in_array($kodeAwal, ['251', '252'])) {
if ($saldo != 0) {
$processedData[] = [
'kode' => $data['kode'],
'kategori' => $kategori,
'debit' => $saldo > 0 ? abs($saldo) : 0,
'kredit' => $saldo < 0 ? abs($saldo) : 0
];
$totalDebit += $saldo > 0 ? abs($saldo) : 0;
$totalKredit += $saldo < 0 ? abs($saldo) : 0;
}
} else {
if ($saldo != 0) {
$processedData[] = [
'kode' => $data['kode'],
'kategori' => $kategori,
'debit' => $saldo < 0 ? abs($saldo) : 0,
'kredit' => $saldo > 0 ? abs($saldo) : 0
];
$totalDebit += $saldo < 0 ? abs($saldo) : 0;
$totalKredit += $saldo > 0 ? abs($saldo) : 0;
}
}
}
// Generate PDF
$html = '
<!DOCTYPE html>
<html>
<head>
<title>Neraca Saldo</title>
<style>
body {
font-family: Arial, sans-serif;
font-size: 12px;
}
h2 {
text-align: center;
margin-bottom: 5px;
}
p.periode {
text-align: center;
margin-top: 0;
margin-bottom: 20px;
font-size: 11px;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
table, th, td {
border: 1px solid #ddd;
}
th, td {
padding: 6px;
text-align: left;
font-size: 10px;
}
th {
background-color: #f2f2f2;
font-weight: bold;
}
.text-right {
text-align: right;
}
tfoot td {
font-weight: bold;
background-color: #f9f9f9;
}
</style>
</head>
<body>
<h2>Neraca Saldo</h2>
<p class="periode">Periode: ' . date('F Y', strtotime($startDate)) . '</p>
<table>
<thead>
<tr>
<th>Kode</th>
<th>Nama Akun</th>
<th class="text-right">Debit</th>
<th class="text-right">Kredit</th>
</tr>
</thead>
<tbody>';
foreach($processedData as $data) {
if ($data['kategori'] !== 'Total') {
$html .= '
<tr>
<td>'.$data['kode'].'</td>
<td>'.$data['kategori'].'</td>
<td class="text-right">'.($data['debit'] > 0 ? 'Rp '.number_format($data['debit'], 0, ',', '.') : '-').'</td>
<td class="text-right">'.($data['kredit'] > 0 ? 'Rp '.number_format($data['kredit'], 0, ',', '.') : '-').'</td>
</tr>';
}
}
$html .= '
</tbody>
<tfoot>
<tr>
<td colspan="2" class="text-right">Total:</td>
<td class="text-right">Rp '.number_format($totalDebit, 0, ',', '.').'</td>
<td class="text-right">Rp '.number_format($totalKredit, 0, ',', '.').'</td>
</tr>
</tfoot>
</table>
</body>
</html>';
$pdf = PDF::loadHTML($html);
return $pdf->download('neraca-saldo-'.date('Y-m-d').'.pdf');
} catch (\Exception $e) {
return redirect()->back()->with('error', 'Gagal mengekspor PDF: ' . $e->getMessage());
}
}
} }

View File

@ -8,6 +8,8 @@
use Carbon\Carbon; use Carbon\Carbon;
use PDF; use PDF;
use Excel; use Excel;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class RekeningController extends Controller class RekeningController extends Controller
{ {
@ -17,6 +19,15 @@ public function index(Request $request)
$startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d')); $startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d'));
$endDate = $request->input('end_date', Carbon::now()->endOfMonth()->format('Y-m-d')); $endDate = $request->input('end_date', Carbon::now()->endOfMonth()->format('Y-m-d'));
// Pastikan tanggal valid
try {
$startDate = Carbon::parse($startDate)->format('Y-m-d');
$endDate = Carbon::parse($endDate)->format('Y-m-d');
} catch (\Exception $e) {
$startDate = Carbon::now()->startOfMonth()->format('Y-m-d');
$endDate = Carbon::now()->endOfMonth()->format('Y-m-d');
}
$query = RekeningModel::whereBetween('Tanggal', [$startDate, $endDate]); $query = RekeningModel::whereBetween('Tanggal', [$startDate, $endDate]);
// Filter berdasarkan nama akun jika ada // Filter berdasarkan nama akun jika ada
@ -98,7 +109,9 @@ public function index(Request $request)
'totals' => $totals, 'totals' => $totals,
'totalDebit' => $totalDebit, 'totalDebit' => $totalDebit,
'totalKredit' => $totalKredit, 'totalKredit' => $totalKredit,
'saldo' => $saldo 'saldo' => $saldo,
'startDate' => $startDate,
'endDate' => $endDate
]); ]);
} }
@ -309,24 +322,299 @@ public function destroy($id)
} }
} }
public function exportExcel() public function exportExcel(Request $request)
{ {
$laporan = RekeningModel::all(); try {
$groupedLaporan = $laporan->groupBy('kategori'); // Ambil parameter filter tanggal jika ada
$startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d'));
$endDate = $request->input('end_date', Carbon::now()->endOfMonth()->format('Y-m-d'));
return Excel::download(function($excel) use ($groupedLaporan) { $laporan = RekeningModel::whereBetween('Tanggal', [$startDate, $endDate])->get();
$excel->sheet('Rekening', function($sheet) use ($groupedLaporan) { $groupedLaporan = collect();
$sheet->loadView('exports.rekening-excel', compact('groupedLaporan'));
}); // Proses data seperti di fungsi index
}, 'rekening-' . Carbon::now()->format('Y-m-d') . '.xlsx'); foreach ($laporan as $item) {
if (!empty($item->kategori)) {
$kategori = $item->kategori;
if (!isset($groupedLaporan[$kategori])) {
$groupedLaporan[$kategori] = collect();
}
$groupedLaporan[$kategori]->push((object)[
'Tanggal' => $item->Tanggal,
'keterangan' => $item->keterangan,
'kode' => $this->generateKode($kategori),
'debit' => $item->uang_masuk ?? 0,
'kredit' => $item->uang_keluar ?? 0
]);
}
// Proses untuk kategori tambahan (2-5)
for ($i = 2; $i <= 5; $i++) {
$kategoriField = "kategori{$i}";
$uangMasukField = "uang_masuk{$i}";
$uangKeluarField = "uang_keluar{$i}";
if (!empty($item->$kategoriField)) {
$kategori = $item->$kategoriField;
if (!isset($groupedLaporan[$kategori])) {
$groupedLaporan[$kategori] = collect();
}
$groupedLaporan[$kategori]->push((object)[
'Tanggal' => $item->Tanggal,
'keterangan' => $item->keterangan,
'kode' => $this->generateKode($kategori),
'debit' => $item->$uangMasukField ?? 0,
'kredit' => $item->$uangKeluarField ?? 0
]);
}
}
}
// Buat class export inline
$export = new class($groupedLaporan) implements FromCollection, WithHeadings {
protected $data;
public function __construct($data)
{
$this->data = $data;
}
public function collection()
{
$exportData = collect();
foreach ($this->data as $kategori => $items) {
// Tambahkan header untuk setiap kategori
$exportData->push([
'Nama Akun: ' . $kategori,
'Kode Akun: ' . ($items->first()->kode ?? '-'),
'', '', '', ''
]);
// Tambahkan header kolom
$exportData->push([
'Tanggal',
'Keterangan',
'Ref',
'Debit',
'Kredit',
'Saldo'
]);
// Tambahkan data transaksi
$runningBalance = 0;
foreach ($items->sortBy('Tanggal') as $item) {
$accountType = substr($item->kode, 0, 3);
$runningBalance = $this->calculateBalance($runningBalance, $item->debit, $item->kredit, $accountType);
$exportData->push([
Carbon::parse($item->Tanggal)->format('d/m/Y'),
$item->keterangan,
'-',
$item->debit > 0 ? number_format($item->debit, 0, ',', '.') : '-',
$item->kredit > 0 ? number_format($item->kredit, 0, ',', '.') : '-',
number_format($runningBalance, 0, ',', '.')
]);
}
// Tambahkan baris kosong setelah setiap kategori
$exportData->push(['', '', '', '', '', '']);
}
return $exportData;
}
public function headings(): array
{
return []; // Header akan ditangani di dalam collection
}
private function calculateBalance($previousBalance, $debit, $kredit, $accountType) {
$balance = $previousBalance;
if (in_array($accountType, ['111', '112']) || in_array($accountType, ['251', '252'])) {
$balance = $balance + $debit - $kredit;
} else {
$balance = $balance - $debit + $kredit;
}
return $balance;
}
};
return Excel::download($export, 'buku-besar-'.date('Y-m-d').'.xlsx');
} catch (\Exception $e) {
return redirect()->back()->with('error', 'Gagal mengekspor Excel: ' . $e->getMessage());
}
} }
public function exportPDF() public function exportPDF(Request $request)
{ {
$laporan = RekeningModel::all(); try {
$groupedLaporan = $laporan->groupBy('kategori'); // Ambil parameter filter tanggal jika ada
$pdf = PDF::loadView('exports.rekening-pdf', compact('groupedLaporan')); $startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d'));
$endDate = $request->input('end_date', Carbon::now()->endOfMonth()->format('Y-m-d'));
return $pdf->download('rekening-' . Carbon::now()->format('Y-m-d') . '.pdf'); $laporan = RekeningModel::whereBetween('Tanggal', [$startDate, $endDate])->get();
$groupedLaporan = collect();
// Proses data seperti di fungsi index
foreach ($laporan as $item) {
if (!empty($item->kategori)) {
$kategori = $item->kategori;
if (!isset($groupedLaporan[$kategori])) {
$groupedLaporan[$kategori] = collect();
}
$groupedLaporan[$kategori]->push((object)[
'Tanggal' => $item->Tanggal,
'keterangan' => $item->keterangan,
'kode' => $this->generateKode($kategori),
'debit' => $item->uang_masuk ?? 0,
'kredit' => $item->uang_keluar ?? 0
]);
}
// Proses untuk kategori tambahan (2-5)
for ($i = 2; $i <= 5; $i++) {
$kategoriField = "kategori{$i}";
$uangMasukField = "uang_masuk{$i}";
$uangKeluarField = "uang_keluar{$i}";
if (!empty($item->$kategoriField)) {
$kategori = $item->$kategoriField;
if (!isset($groupedLaporan[$kategori])) {
$groupedLaporan[$kategori] = collect();
}
$groupedLaporan[$kategori]->push((object)[
'Tanggal' => $item->Tanggal,
'keterangan' => $item->keterangan,
'kode' => $this->generateKode($kategori),
'debit' => $item->$uangMasukField ?? 0,
'kredit' => $item->$uangKeluarField ?? 0
]);
}
}
}
// Generate PDF
$html = '
<!DOCTYPE html>
<html>
<head>
<title>Buku Besar</title>
<style>
body {
font-family: Arial, sans-serif;
font-size: 12px;
}
h2 {
text-align: center;
margin-bottom: 5px;
}
p.periode {
text-align: center;
margin-top: 0;
margin-bottom: 20px;
font-size: 11px;
}
.account-info {
background-color: #f2f2f2;
padding: 8px;
margin-bottom: 10px;
border-radius: 4px;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
page-break-inside: avoid;
}
table, th, td {
border: 1px solid #ddd;
}
th, td {
padding: 6px;
text-align: left;
font-size: 10px;
}
th {
background-color: #f2f2f2;
font-weight: bold;
}
.text-right {
text-align: right;
}
.text-center {
text-align: center;
}
.page-break {
page-break-after: always;
}
</style>
</head>
<body>
<h2>Buku Besar</h2>
<p class="periode">Periode: ' . date('F Y', strtotime($startDate)) . '</p>';
foreach($groupedLaporan as $kategori => $items) {
$kodeAkun = $items->first()->kode ?? '-';
$html .= '
<div class="account-info">
<strong>Nama Akun:</strong> ' . $kategori . '
<span style="float: right;"><strong>Kode Akun:</strong> ' . $kodeAkun . '</span>
</div>
<table>
<thead>
<tr>
<th>Tanggal</th>
<th>Keterangan</th>
<th class="text-center">Ref</th>
<th class="text-right">Debit</th>
<th class="text-right">Kredit</th>
<th class="text-right">Saldo</th>
</tr>
</thead>
<tbody>';
$runningBalance = 0;
$accountType = substr($kodeAkun, 0, 3);
foreach($items->sortBy('Tanggal') as $item) {
if (in_array($accountType, ['111', '112']) || in_array($accountType, ['251', '252'])) {
$runningBalance = $runningBalance + $item->debit - $item->kredit;
} else {
$runningBalance = $runningBalance - $item->debit + $item->kredit;
}
$html .= '
<tr>
<td>' . date('d/m/Y', strtotime($item->Tanggal)) . '</td>
<td>' . $item->keterangan . '</td>
<td class="text-center">-</td>
<td class="text-right">' . ($item->debit > 0 ? number_format($item->debit, 0, ',', '.') : '-') . '</td>
<td class="text-right">' . ($item->kredit > 0 ? number_format($item->kredit, 0, ',', '.') : '-') . '</td>
<td class="text-right">' . number_format($runningBalance, 0, ',', '.') . '</td>
</tr>';
}
$html .= '
</tbody>
</table>';
}
$html .= '
</body>
</html>';
$pdf = PDF::loadHTML($html);
return $pdf->download('buku-besar-'.date('Y-m-d').'.pdf');
} catch (\Exception $e) {
return redirect()->back()->with('error', 'Gagal mengekspor PDF: ' . $e->getMessage());
}
} }
} }

View File

@ -12,16 +12,41 @@ class UserController extends Controller
{ {
public function index() public function index()
{ {
$users = User::all(); return view('User');
return view('User', compact('users'));
} }
public function getData() public function getData(Request $request)
{ {
$users = User::all(); $query = User::select('id', 'nama', 'email', 'tipe_pengguna');
// Apply type filter
if ($request->has('type') && !empty($request->type)) {
$query->where('tipe_pengguna', $request->type);
}
// Apply search filter
if ($request->has('search') && !empty($request->search)) {
$search = $request->search;
$query->where(function($q) use ($search) {
$q->where('nama', 'like', "%{$search}%")
->orWhere('email', 'like', "%{$search}%");
});
}
$users = $query->get();
return response()->json($users); return response()->json($users);
} }
public function show($id)
{
try {
$user = User::findOrFail($id);
return response()->json($user);
} catch (\Exception $e) {
return response()->json(['error' => 'User tidak ditemukan'], 404);
}
}
public function create() public function create()
{ {
return view('TambahAkun'); return view('TambahAkun');
@ -34,22 +59,13 @@ public function store(Request $request)
'email' => ['required', 'string', 'email', 'max:255', 'unique:penggunas'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:penggunas'],
'password' => ['required', Password::min(8)->mixedCase()->numbers()], 'password' => ['required', Password::min(8)->mixedCase()->numbers()],
'tipe_pengguna' => ['required', 'in:owner,karyawan'] 'tipe_pengguna' => ['required', 'in:owner,karyawan']
], [
'nama.required' => 'Nama harus diisi',
'nama.max' => 'Nama maksimal 255 karakter',
'email.required' => 'Email harus diisi',
'email.email' => 'Format email tidak valid',
'email.unique' => 'Email sudah terdaftar',
'password.required' => 'Password harus diisi',
'password.min' => 'Password minimal 8 karakter',
'tipe_pengguna.required' => 'Tipe pengguna harus dipilih',
'tipe_pengguna.in' => 'Tipe pengguna tidak valid'
]); ]);
if ($validator->fails()) { if ($validator->fails()) {
return redirect()->back() return response()->json([
->withErrors($validator) 'success' => false,
->withInput(); 'message' => $validator->errors()->first()
], 422);
} }
try { try {
@ -60,12 +76,15 @@ public function store(Request $request)
'tipe_pengguna' => $request->tipe_pengguna 'tipe_pengguna' => $request->tipe_pengguna
]); ]);
return redirect()->route('User.index') return response()->json([
->with('success', 'Akun berhasil ditambahkan!'); 'success' => true,
'message' => 'User berhasil ditambahkan'
]);
} catch (\Exception $e) { } catch (\Exception $e) {
return redirect()->back() return response()->json([
->with('error', 'Gagal menambahkan akun. ' . $e->getMessage()) 'success' => false,
->withInput(); 'message' => 'Gagal menambahkan user: ' . $e->getMessage()
], 500);
} }
} }
@ -82,21 +101,13 @@ public function update(Request $request, $id)
'email' => ['required', 'string', 'email', 'max:255', 'unique:penggunas,email,'.$id], 'email' => ['required', 'string', 'email', 'max:255', 'unique:penggunas,email,'.$id],
'password' => ['nullable', Password::min(8)->mixedCase()->numbers()], 'password' => ['nullable', Password::min(8)->mixedCase()->numbers()],
'tipe_pengguna' => ['required', 'in:owner,karyawan'] 'tipe_pengguna' => ['required', 'in:owner,karyawan']
], [
'nama.required' => 'Nama harus diisi',
'nama.max' => 'Nama maksimal 255 karakter',
'email.required' => 'Email harus diisi',
'email.email' => 'Format email tidak valid',
'email.unique' => 'Email sudah terdaftar',
'password.min' => 'Password minimal 8 karakter',
'tipe_pengguna.required' => 'Tipe pengguna harus dipilih',
'tipe_pengguna.in' => 'Tipe pengguna tidak valid'
]); ]);
if ($validator->fails()) { if ($validator->fails()) {
return redirect()->back() return response()->json([
->withErrors($validator) 'success' => false,
->withInput(); 'message' => $validator->errors()->first()
], 422);
} }
try { try {
@ -108,19 +119,21 @@ public function update(Request $request, $id)
'tipe_pengguna' => $request->tipe_pengguna 'tipe_pengguna' => $request->tipe_pengguna
]; ];
// Update password hanya jika diisi
if ($request->filled('password')) { if ($request->filled('password')) {
$data['password'] = Hash::make($request->password); $data['password'] = Hash::make($request->password);
} }
$user->update($data); $user->update($data);
return redirect()->route('User.index') return response()->json([
->with('success', 'Akun berhasil diperbarui!'); 'success' => true,
'message' => 'User berhasil diperbarui'
]);
} catch (\Exception $e) { } catch (\Exception $e) {
return redirect()->back() return response()->json([
->with('error', 'Gagal memperbarui akun. ' . $e->getMessage()) 'success' => false,
->withInput(); 'message' => 'Gagal memperbarui user: ' . $e->getMessage()
], 500);
} }
} }
@ -130,11 +143,15 @@ public function destroy($id)
$user = User::findOrFail($id); $user = User::findOrFail($id);
$user->delete(); $user->delete();
return redirect()->route('User.index') return response()->json([
->with('success', 'Akun berhasil dihapus!'); 'success' => true,
'message' => 'User berhasil dihapus'
]);
} catch (\Exception $e) { } catch (\Exception $e) {
return redirect()->back() return response()->json([
->with('error', 'Gagal menghapus akun. ' . $e->getMessage()); 'success' => false,
'message' => 'Gagal menghapus user: ' . $e->getMessage()
], 500);
} }
} }
} }

View File

@ -357,10 +357,10 @@
<!-- Action Buttons --> <!-- Action Buttons -->
<div class="flex justify-between items-center mt-4 mb-4"> <div class="flex justify-between items-center mt-4 mb-4">
<div class="flex space-x-2"> <div class="flex space-x-2">
<a href="{{ route('laporan.export-excel') }}" class="btn bg-green-500 text-white hover:bg-green-600"> <a href="{{ route('laporan.export-excel', ['start_date' => $startDate, 'end_date' => $endDate]) }}" class="btn bg-green-500 text-white hover:bg-green-600">
<i class="fas fa-file-excel mr-2"></i>Export Excel <i class="fas fa-file-excel mr-2"></i>Export Excel
</a> </a>
<a href="{{ route('laporan.export-pdf') }}" class="btn bg-red-500 text-white hover:bg-red-600"> <a href="{{ route('laporan.export-pdf', ['start_date' => $startDate, 'end_date' => $endDate]) }}" class="btn bg-red-500 text-white hover:bg-red-600">
<i class="fas fa-file-pdf mr-2"></i>Export PDF <i class="fas fa-file-pdf mr-2"></i>Export PDF
</a> </a>
<button onclick="window.print()" class="btn bg-gray-500 text-white hover:bg-gray-600"> <button onclick="window.print()" class="btn bg-gray-500 text-white hover:bg-gray-600">
@ -372,21 +372,86 @@
<!-- Style untuk print --> <!-- Style untuk print -->
<style> <style>
@media print { @media print {
.btn, header, footer, .no-print { .btn, header, footer, .no-print, nav, .aside, #prevPage, #nextPage, #rowsPerPage {
display: none !important; display: none !important;
} }
body { body {
padding: 20px; padding: 20px;
font-size: 14px; font-size: 12px;
background-color: white !important;
}
.box, .p-4, .intro-y {
padding: 0 !important;
margin: 0 !important;
background-color: white !important;
}
.bg-gray-100 {
background-color: white !important;
}
h1.text-2xl {
text-align: center;
font-size: 20px;
margin: 10px 0 5px 0;
font-weight: bold;
}
p.text-sm {
text-align: center;
margin: 5px 0 20px 0;
font-size: 12px;
} }
.print-table { .print-table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse !important;
margin-bottom: 20px;
}
table {
font-size: 10px !important;
} }
.print-table th, .print-table th,
.print-table td { .print-table td,
border: 1px solid #000; table th,
padding: 8px; table td {
border: 1px solid #000 !important;
padding: 6px !important;
}
.print-table th,
table th {
text-align: left;
background-color: #f2f2f2 !important;
font-weight: bold;
-webkit-print-color-adjust: exact;
color-adjust: exact;
print-color-adjust: exact;
}
.text-right,
table td:nth-child(6),
table td:nth-child(7),
table th:nth-child(6),
table th:nth-child(7) {
text-align: right !important;
}
.text-center,
table td:nth-child(1),
table th:nth-child(1) {
text-align: center !important;
}
.py-3, .px-4 {
padding: 6px !important;
}
tfoot td,
table tr:last-child td {
font-weight: bold !important;
background-color: #f9f9f9 !important;
-webkit-print-color-adjust: exact;
color-adjust: exact;
print-color-adjust: exact;
}
.bg-blue-600 {
background-color: white !important;
box-shadow: none !important;
}
.ml-8 {
margin-left: 8px !important;
} }
} }
</style> </style>

View File

@ -101,10 +101,10 @@
<!-- Action Buttons --> <!-- Action Buttons -->
<div class="flex justify-between items-center mt-4 mb-4"> <div class="flex justify-between items-center mt-4 mb-4">
<div class="flex space-x-2"> <div class="flex space-x-2">
<a href="{{ route('laporan.export-excel') }}" class="btn bg-green-500 text-white hover:bg-green-600"> <a href="{{ route('neracasaldo.export-excel', ['start_date' => $startDate, 'end_date' => $endDate]) }}" class="btn bg-green-500 text-white hover:bg-green-600">
<i class="fas fa-file-excel mr-2"></i>Export Excel <i class="fas fa-file-excel mr-2"></i>Export Excel
</a> </a>
<a href="{{ route('laporan.export-pdf') }}" class="btn bg-red-500 text-white hover:bg-red-600"> <a href="{{ route('neracasaldo.export-pdf', ['start_date' => $startDate, 'end_date' => $endDate]) }}" class="btn bg-red-500 text-white hover:bg-red-600">
<i class="fas fa-file-pdf mr-2"></i>Export PDF <i class="fas fa-file-pdf mr-2"></i>Export PDF
</a> </a>
<button onclick="window.print()" class="btn bg-gray-500 text-white hover:bg-gray-600"> <button onclick="window.print()" class="btn bg-gray-500 text-white hover:bg-gray-600">
@ -112,4 +112,73 @@
</button> </button>
</div> </div>
</div> </div>
<!-- Style untuk print -->
<style>
@media print {
.btn, header, footer, .no-print, nav, .aside, #prevPage, #nextPage, #rowsPerPage {
display: none !important;
}
body {
padding: 20px;
font-size: 12px;
background-color: white !important;
}
.box, .p-4, .intro-y {
padding: 0 !important;
margin: 0 !important;
background-color: white !important;
}
.bg-gray-100 {
background-color: white !important;
}
h1.text-2xl {
text-align: center;
font-size: 20px;
margin: 10px 0 5px 0;
font-weight: bold;
}
p.text-sm {
text-align: center;
margin: 5px 0 20px 0;
font-size: 12px;
}
table {
width: 100%;
border-collapse: collapse !important;
margin-bottom: 20px;
font-size: 10px !important;
}
table th,
table td {
border: 1px solid #000 !important;
padding: 6px !important;
}
table th {
text-align: left;
background-color: #f2f2f2 !important;
font-weight: bold;
-webkit-print-color-adjust: exact;
color-adjust: exact;
print-color-adjust: exact;
}
table td:nth-child(3),
table td:nth-child(4),
table th:nth-child(3),
table th:nth-child(4) {
text-align: right !important;
}
table tr:last-child td {
font-weight: bold !important;
background-color: #f9f9f9 !important;
-webkit-print-color-adjust: exact;
color-adjust: exact;
print-color-adjust: exact;
}
.bg-blue-600 {
background-color: white !important;
box-shadow: none !important;
}
}
</style>
@endsection @endsection

View File

@ -165,10 +165,10 @@ function calculateBalancePHP($previousBalance, $debit, $kredit, $accountType) {
<!-- Action Buttons --> <!-- Action Buttons -->
<div class="flex justify-between items-center mt-4 mb-4"> <div class="flex justify-between items-center mt-4 mb-4">
<div class="flex space-x-2"> <div class="flex space-x-2">
<a href="{{ route('laporan.export-excel') }}" class="btn bg-green-500 text-white hover:bg-green-600 px-4 py-2 rounded-md"> <a href="{{ route('rekening.export-excel', ['start_date' => $startDate, 'end_date' => $endDate]) }}" class="btn bg-green-500 text-white hover:bg-green-600 px-4 py-2 rounded-md">
<i class="fas fa-file-excel mr-2"></i>Export Excel <i class="fas fa-file-excel mr-2"></i>Export Excel
</a> </a>
<a href="{{ route('laporan.export-pdf') }}" class="btn bg-red-500 text-white hover:bg-red-600 px-4 py-2 rounded-md"> <a href="{{ route('rekening.export-pdf', ['start_date' => $startDate, 'end_date' => $endDate]) }}" class="btn bg-red-500 text-white hover:bg-red-600 px-4 py-2 rounded-md">
<i class="fas fa-file-pdf mr-2"></i>Export PDF <i class="fas fa-file-pdf mr-2"></i>Export PDF
</a> </a>
<button onclick="window.print()" class="btn bg-gray-500 text-white hover:bg-gray-600 px-4 py-2 rounded-md"> <button onclick="window.print()" class="btn bg-gray-500 text-white hover:bg-gray-600 px-4 py-2 rounded-md">
@ -181,24 +181,71 @@ function calculateBalancePHP($previousBalance, $debit, $kredit, $accountType) {
<style> <style>
@media print { @media print {
.btn, header, footer, .no-print { .btn, header, footer, .no-print, nav, .aside {
display: none !important; display: none !important;
} }
body { body {
padding: 20px; padding: 20px;
font-size: 14px; font-size: 12px;
} }
.box { .box {
box-shadow: none !important; box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
}
h1.text-2xl {
text-align: center;
font-size: 20px;
margin: 10px 0 5px 0;
font-weight: bold;
}
p.text-sm {
text-align: center;
margin: 5px 0 20px 0;
font-size: 12px;
}
.account-info {
background-color: #f2f2f2 !important;
padding: 8px;
margin-bottom: 10px;
border-radius: 4px;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
} }
table { table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
margin-bottom: 20px;
page-break-inside: avoid; page-break-inside: avoid;
font-size: 10px !important;
}
table, th, td {
border: 1px solid #000 !important;
} }
th, td { th, td {
border: 1px solid #000; padding: 6px !important;
padding: 8px; }
th {
background-color: #f2f2f2 !important;
font-weight: bold;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
.text-right {
text-align: right !important;
}
.text-center {
text-align: center !important;
}
.bg-blue-600 {
background-color: white !important;
box-shadow: none !important;
}
.mb-8 {
margin-bottom: 20px !important;
}
.page-break {
page-break-after: always;
} }
} }
</style> </style>

View File

@ -5,6 +5,9 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
<!-- SweetAlert2 JS --> <!-- SweetAlert2 JS -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
<style> <style>
/* Gradient Background */ /* Gradient Background */
body { body {
@ -21,6 +24,7 @@
/* Table Styling */ /* Table Styling */
.print-table { .print-table {
border-collapse: collapse; border-collapse: collapse;
width: 100%;
} }
.print-table th { .print-table th {
@ -48,6 +52,9 @@
border-radius: 0.375rem; border-radius: 0.375rem;
font-weight: 500; font-weight: 500;
transition: all 0.3s ease; transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
} }
.btn-primary { .btn-primary {
@ -59,80 +66,46 @@
background-color: #2563eb; background-color: #2563eb;
} }
/* Modal Styling */ /* Filter Controls */
.modal { .filter-controls {
display: none; display: flex;
position: fixed; gap: 1rem;
top: 0; margin-bottom: 1.5rem;
right: 0; flex-wrap: wrap;
bottom: 0;
left: 0;
z-index: 50;
background-color: rgba(0, 0, 0, 0.5);
} }
.modal.show { .filter-group {
display: block; display: flex;
align-items: center;
gap: 0.5rem;
} }
.modal-slide-over { .filter-input {
transform: translateX(100%); border: 1px solid #e5e7eb;
transition: transform 0.3s ease-out; border-radius: 0.375rem;
padding: 0.5rem;
min-width: 200px;
} }
.modal.show .modal-slide-over { .filter-input:focus {
transform: translateX(0); outline: none;
} border-color: #3b82f6;
ring: 2px;
/* Animation */ ring-color: #93c5fd;
.intro-y {
animation: fadeIn 0.5s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Custom Scrollbar */
.overflow-x-auto::-webkit-scrollbar {
height: 8px;
}
.overflow-x-auto::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
.overflow-x-auto::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
.overflow-x-auto::-webkit-scrollbar-thumb:hover {
background: #555;
} }
/* Responsive Design */ /* Responsive Design */
@media (max-width: 640px) { @media (max-width: 640px) {
.box { .filter-controls {
margin: 0.5rem; flex-direction: column;
padding: 0.5rem;
} }
.print-table { .filter-group {
font-size: 0.875rem; width: 100%;
} }
.print-table th, .filter-input {
.print-table td { width: 100%;
padding: 0.5rem;
} }
} }
</style> </style>
@ -144,158 +117,135 @@
<h1 class="text-2xl font-bold">Akun User</h1> <h1 class="text-2xl font-bold">Akun User</h1>
<p class="text-sm mt-1">Halaman ini menampilkan dan mengelola akun user.</p> <p class="text-sm mt-1">Halaman ini menampilkan dan mengelola akun user.</p>
</div> </div>
<!-- Form Section for Creating User -->
<div class="flex flex-wrap gap-4 px-6 py-4 border-b border-gray-200"> <!-- Filter dan Tombol Tambah -->
<div class="flex items-center"> <div class="filter-controls">
<label class="mr-2 text-sm font-medium text-gray-600">Nama:</label> <div class="filter-group">
<input type="text" id="userName" class="border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Nama User"> <label for="userType" class="font-medium">Tipe User:</label>
</div> <select id="userType" class="filter-input">
<div class="flex items-center"> <option value="">Semua</option>
<label class="mr-2 text-sm font-medium text-gray-600">Email:</label>
<input type="email" id="userEmail" class="border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Email User">
</div>
<div class="flex items-center">
<label class="mr-2 text-sm font-medium text-gray-600">Password:</label>
<input type="password" id="userPassword" class="border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Password User">
</div>
<div class="flex items-center">
<label class="mr-2 text-sm font-medium text-gray-600">Tipe Pengguna:</label>
<select id="userType" class="border rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="karyawan">Karyawan</option> <option value="karyawan">Karyawan</option>
<option value="owner">Owner</option> <option value="owner">Owner</option>
</select> </select>
</div> </div>
<button id="createUser" class="btn btn-primary">Buat Akun</button>
<div class="filter-group">
<label for="searchUser" class="font-medium">Cari:</label>
<input type="text" id="searchUser" class="filter-input" placeholder="Cari nama/email...">
</div>
<div class="filter-group ml-auto">
<a href="{{ route('User.create') }}" id="createUser" class="btn btn-primary">
<i class="fas fa-plus"></i>
<span>Tambah User</span>
</a>
</div>
</div> </div>
<!-- Tabel User -->
<div class="overflow-x-auto"> <div class="overflow-x-auto">
<table class="w-full bg-white border border-gray-300 print-table"> <table class="print-table">
<thead> <thead>
<tr class="bg-gray-100 text-gray-600 uppercase text-sm leading-normal"> <tr>
<th class="py-3 px-4 text-left">No</th> <th class="text-left">No</th>
<th class="py-3 px-4 text-left">Nama</th> <th class="text-left">Nama</th>
<th class="py-3 px-4 text-left">Email</th> <th class="text-left">Email</th>
<th class="py-3 px-4 text-left">Tipe Pengguna</th> <th class="text-left">Tipe User</th>
<th class="py-3 px-4 text-center">Aksi</th> <th class="text-center">Aksi</th>
</tr> </tr>
</thead> </thead>
<tbody id="userTableBody"> <tbody id="userTableBody">
<!-- User data will be populated here --> <!-- Data akan diisi melalui JavaScript -->
</tbody> </tbody>
</table> </table>
</div> </div>
<!-- Pagination -->
<div class="intro-y col-span-12 flex flex-wrap sm:flex-row sm:flex-nowrap items-center py-5 px-4">
<!-- ... existing pagination code ... -->
</div>
</div> </div>
</div> </div>
<!-- JavaScript for handling user CRUD operations -->
<script> <script>
// Notifikasi SweetAlert2 document.addEventListener('DOMContentLoaded', function() {
@if(session('success')) const userType = document.getElementById('userType');
Swal.fire({ const searchUser = document.getElementById('searchUser');
icon: 'success',
title: 'Berhasil!', // Load initial data
text: '{{ session('success') }}', loadUsers();
confirmButtonText: 'OK'
// Event listeners for filters
userType.addEventListener('change', () => {
loadUsers(userType.value, searchUser.value);
}); });
@endif
@if(session('error')) searchUser.addEventListener('input', () => {
Swal.fire({ loadUsers(userType.value, searchUser.value);
icon: 'error',
title: 'Gagal!',
text: '{{ session('error') }}',
confirmButtonText: 'OK'
}); });
@endif
// Function to load users
function loadUsers() {
fetch('/users/data')
.then(response => response.json())
.then(data => {
const userTableBody = document.getElementById('userTableBody');
userTableBody.innerHTML = '';
data.forEach((user, index) => {
userTableBody.innerHTML += `
<tr class="border-b border-gray-200 hover:bg-gray-50">
<td class="py-3 px-4">${index + 1}</td>
<td class="py-3 px-4">${user.nama}</td>
<td class="py-3 px-4">${user.email}</td>
<td class="py-3 px-4">${user.tipe_pengguna}</td>
<td class="py-3 px-4 text-center">
<button onclick="editUser(${user.id})" class="text-blue-600 hover:text-blue-800">
<i class="fas fa-edit"></i>
</button>
<button onclick="deleteUser(${user.id})" class="text-red-600 hover:text-red-800">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
`;
});
})
.catch(error => console.error("Error fetching data:", error));
}
// Function untuk mengedit user
function editUser(id) {
window.location.href = `/User/${id}/edit`;
}
// Event listener for creating a user
document.getElementById('createUser').addEventListener('click', () => {
const nama = document.getElementById('userName').value;
const email = document.getElementById('userEmail').value;
const password = document.getElementById('userPassword').value;
const tipe_pengguna = document.getElementById('userType').value;
// Redirect ke route User.create
window.location.href = "{{ route('User.create') }}";
}); });
// Function untuk menghapus user function loadUsers(typeFilter = '', searchFilter = '') {
fetch(`/users/data?type=${typeFilter}&search=${searchFilter}`)
.then(response => response.json())
.then(data => {
const tbody = document.getElementById('userTableBody');
tbody.innerHTML = '';
data.forEach((user, index) => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${index + 1}</td>
<td>${user.nama}</td>
<td>${user.email}</td>
<td>${user.tipe_pengguna}</td>
<td class="text-center">
<a href="/User/${user.id}/edit" class="text-blue-600 hover:text-blue-800 mx-1">
<i class="fas fa-edit"></i>
</a>
<button onclick="deleteUser(${user.id})" class="text-red-600 hover:text-red-800 mx-1">
<i class="fas fa-trash"></i>
</button>
</td>
`;
tbody.appendChild(row);
});
})
.catch(error => {
console.error('Error loading users:', error);
Swal.fire('Error!', 'Gagal memuat data user', 'error');
});
}
function deleteUser(id) { function deleteUser(id) {
Swal.fire({ Swal.fire({
title: 'Apakah Anda yakin?', title: 'Hapus User',
text: "Data yang dihapus tidak dapat dikembalikan!", text: 'Apakah Anda yakin ingin menghapus user ini?',
icon: 'warning', icon: 'warning',
showCancelButton: true, showCancelButton: true,
confirmButtonColor: '#3085d6', confirmButtonText: 'Ya, Hapus',
cancelButtonColor: '#d33',
confirmButtonText: 'Ya, hapus!',
cancelButtonText: 'Batal' cancelButtonText: 'Batal'
}).then((result) => { }).then((result) => {
if (result.isConfirmed) { if (result.isConfirmed) {
// Buat form untuk delete request fetch(`/User/${id}`, {
const form = document.createElement('form'); method: 'DELETE',
form.method = 'POST'; headers: {
form.action = `/User/${id}`; 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
}
const csrfToken = document.createElement('input'); })
csrfToken.type = 'hidden'; .then(response => response.json())
csrfToken.name = '_token'; .then(data => {
csrfToken.value = '{{ csrf_token() }}'; if (data.success) {
loadUsers(
const methodField = document.createElement('input'); document.getElementById('userType').value,
methodField.type = 'hidden'; document.getElementById('searchUser').value
methodField.name = '_method'; );
methodField.value = 'DELETE'; Swal.fire('Berhasil!', 'User telah dihapus', 'success');
} else {
form.appendChild(csrfToken); throw new Error(data.message || 'Gagal menghapus user');
form.appendChild(methodField); }
document.body.appendChild(form); })
form.submit(); .catch(error => {
console.error('Error deleting user:', error);
Swal.fire('Error!', 'Gagal menghapus user', 'error');
});
} }
}); });
} }
// Initial load
loadUsers();
</script> </script>
@endsection @endsection

View File

@ -77,6 +77,8 @@
// Routes untuk Neraca Saldo // Routes untuk Neraca Saldo
Route::get('/neracasaldo/filter', [NeracasaldoController::class, 'filter'])->name('neracasaldo.filter'); Route::get('/neracasaldo/filter', [NeracasaldoController::class, 'filter'])->name('neracasaldo.filter');
Route::get('/neracasaldo/export-excel', [NeracasaldoController::class, 'exportExcel'])->name('neracasaldo.export-excel');
Route::get('/neracasaldo/export-pdf', [NeracasaldoController::class, 'exportPDF'])->name('neracasaldo.export-pdf');
Route::resource('neracasaldo', NeracasaldoController::class); Route::resource('neracasaldo', NeracasaldoController::class);
// Routes untuk Laba Rugi // Routes untuk Laba Rugi