update tgl 8 mei
This commit is contained in:
parent
0be2b98301
commit
514596bce8
|
@ -173,17 +173,21 @@ public function index(Request $request)
|
|||
}
|
||||
}
|
||||
|
||||
// Get monthly totals for chart
|
||||
// Get daily totals for chart
|
||||
$monthlyTotals = DB::table('laporan_transaksis')
|
||||
->select(
|
||||
DB::raw('DATE_FORMAT(Tanggal, "%Y-%m") as periode'),
|
||||
DB::raw('SUM(CASE WHEN LEFT(kategori, 3) IN ("241", "242") THEN uang_masuk ELSE 0 END) as total_debit'),
|
||||
DB::raw('SUM(CASE WHEN LEFT(kategori, 3) IN ("251", "252") THEN uang_keluar ELSE 0 END) as total_kredit')
|
||||
DB::raw('DATE_FORMAT(Tanggal, "%Y-%m-%d") as periode'),
|
||||
DB::raw('SUM(uang_masuk) as total_debit'),
|
||||
DB::raw('SUM(uang_keluar) as total_kredit')
|
||||
)
|
||||
->whereBetween('Tanggal', [$startDate, $endDate])
|
||||
->groupBy('periode')
|
||||
->orderBy('periode')
|
||||
->get();
|
||||
|
||||
// Debug untuk memastikan data terisi
|
||||
Log::info('Daily Totals:', ['data' => $monthlyTotals->toArray()]);
|
||||
|
||||
// Get category totals for distribution chart
|
||||
$categoryTotals = DB::table('laporan_transaksis')
|
||||
->select(
|
||||
|
@ -242,6 +246,63 @@ public function index(Request $request)
|
|||
(($currentMonthLabaRugi - $lastMonthLabaRugi) / abs($lastMonthLabaRugi)) * 100 :
|
||||
100;
|
||||
|
||||
// Ambil data neraca saldo untuk pie chart
|
||||
$rawTransaksis = DB::table('laporan_transaksis')
|
||||
->whereBetween('Tanggal', [$startDate, $endDate])
|
||||
->orderBy('kode', 'asc')
|
||||
->get();
|
||||
$totalsPerAkun = [];
|
||||
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);
|
||||
}
|
||||
$finalTransaksis = [];
|
||||
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) {
|
||||
$finalTransaksis[] = [
|
||||
'kode' => $data['kode'],
|
||||
'kategori' => $kategori,
|
||||
'debit' => $saldo,
|
||||
'kredit' => 0
|
||||
];
|
||||
}
|
||||
} else {
|
||||
if ($saldo != 0) {
|
||||
$finalTransaksis[] = [
|
||||
'kode' => $data['kode'],
|
||||
'kategori' => $kategori,
|
||||
'debit' => 0,
|
||||
'kredit' => -$saldo
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
$neracaTransaksis = collect($finalTransaksis);
|
||||
$pieLabels = $neracaTransaksis->pluck('kategori')->toArray();
|
||||
$pieData = $neracaTransaksis->map(function($item) {
|
||||
return abs($item['debit']) + abs($item['kredit']);
|
||||
})->toArray();
|
||||
|
||||
return view('home', compact(
|
||||
'startDate',
|
||||
'endDate',
|
||||
|
@ -254,7 +315,9 @@ public function index(Request $request)
|
|||
'categoryTotals',
|
||||
'recentTransactions',
|
||||
'pendapatan',
|
||||
'beban'
|
||||
'beban',
|
||||
'pieLabels',
|
||||
'pieData'
|
||||
));
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
|
|
@ -134,4 +134,202 @@ public function filter(Request $request)
|
|||
{
|
||||
return $this->index($request);
|
||||
}
|
||||
|
||||
public function exportExcel(Request $request)
|
||||
{
|
||||
try {
|
||||
$startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d'));
|
||||
$endDate = $request->input('end_date', Carbon::now()->endOfMonth()->format('Y-m-d'));
|
||||
|
||||
// Inisialisasi array untuk menyimpan data
|
||||
$pendapatan = [];
|
||||
$beban = [];
|
||||
|
||||
// Ambil semua transaksi dalam periode
|
||||
$transaksis = DB::table('laporan_transaksis')
|
||||
->whereBetween('Tanggal', [$startDate, $endDate])
|
||||
->get();
|
||||
|
||||
foreach ($transaksis as $transaksi) {
|
||||
// Proses kategori1
|
||||
if (!empty($transaksi->kategori)) {
|
||||
$this->prosesKategori(
|
||||
$transaksi->kategori,
|
||||
$transaksi->uang_masuk ?? 0,
|
||||
$transaksi->uang_keluar ?? 0,
|
||||
$pendapatan,
|
||||
$beban
|
||||
);
|
||||
}
|
||||
|
||||
// Proses kategori2-5
|
||||
for ($i = 2; $i <= 5; $i++) {
|
||||
$kategori = $transaksi->{"kategori$i"};
|
||||
if (!empty($kategori)) {
|
||||
$this->prosesKategori(
|
||||
$kategori,
|
||||
$transaksi->{"uang_masuk$i"} ?? 0,
|
||||
$transaksi->{"uang_keluar$i"} ?? 0,
|
||||
$pendapatan,
|
||||
$beban
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hitung total
|
||||
$total_pendapatan = array_sum(array_column($pendapatan, 'nominal'));
|
||||
$total_beban = abs(array_sum(array_column($beban, 'nominal')));
|
||||
$laba_rugi = $total_pendapatan - $total_beban;
|
||||
|
||||
// Siapkan data untuk Excel
|
||||
$rows = [];
|
||||
|
||||
// Header
|
||||
$rows[] = ['Laporan Laba Rugi'];
|
||||
$rows[] = ['Periode: ' . date('F Y', strtotime($startDate))];
|
||||
$rows[] = []; // Baris kosong
|
||||
|
||||
// Pendapatan
|
||||
$rows[] = ['Pendapatan'];
|
||||
foreach ($pendapatan as $item) {
|
||||
$rows[] = [
|
||||
ucwords($item['kategori']),
|
||||
number_format(abs($item['nominal']), 0, ',', '.')
|
||||
];
|
||||
}
|
||||
$rows[] = ['Total Pendapatan', number_format(abs($total_pendapatan), 0, ',', '.')];
|
||||
$rows[] = []; // Baris kosong
|
||||
|
||||
// Beban
|
||||
$rows[] = ['Beban'];
|
||||
foreach ($beban as $item) {
|
||||
$rows[] = [
|
||||
ucwords($item['kategori']),
|
||||
number_format(abs($item['nominal']), 0, ',', '.')
|
||||
];
|
||||
}
|
||||
$rows[] = ['Total Beban', number_format($total_beban, 0, ',', '.')];
|
||||
$rows[] = []; // Baris kosong
|
||||
|
||||
// Laba/Rugi
|
||||
$rows[] = ['Laba/Rugi Bersih', number_format($laba_rugi, 0, ',', '.')];
|
||||
|
||||
$export = new class($rows) implements \Maatwebsite\Excel\Concerns\FromArray {
|
||||
protected $rows;
|
||||
public function __construct($rows) { $this->rows = $rows; }
|
||||
public function array(): array { return $this->rows; }
|
||||
};
|
||||
|
||||
return \Maatwebsite\Excel\Facades\Excel::download($export, 'laporan-laba-rugi-'.date('Y-m-d').'.xlsx');
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->back()->with('error', 'Gagal mengekspor Excel: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function exportPDF(Request $request)
|
||||
{
|
||||
try {
|
||||
$startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d'));
|
||||
$endDate = $request->input('end_date', Carbon::now()->endOfMonth()->format('Y-m-d'));
|
||||
|
||||
// Inisialisasi array untuk menyimpan data
|
||||
$pendapatan = [];
|
||||
$beban = [];
|
||||
|
||||
// Ambil semua transaksi dalam periode
|
||||
$transaksis = DB::table('laporan_transaksis')
|
||||
->whereBetween('Tanggal', [$startDate, $endDate])
|
||||
->get();
|
||||
|
||||
foreach ($transaksis as $transaksi) {
|
||||
// Proses kategori1
|
||||
if (!empty($transaksi->kategori)) {
|
||||
$this->prosesKategori(
|
||||
$transaksi->kategori,
|
||||
$transaksi->uang_masuk ?? 0,
|
||||
$transaksi->uang_keluar ?? 0,
|
||||
$pendapatan,
|
||||
$beban
|
||||
);
|
||||
}
|
||||
|
||||
// Proses kategori2-5
|
||||
for ($i = 2; $i <= 5; $i++) {
|
||||
$kategori = $transaksi->{"kategori$i"};
|
||||
if (!empty($kategori)) {
|
||||
$this->prosesKategori(
|
||||
$kategori,
|
||||
$transaksi->{"uang_masuk$i"} ?? 0,
|
||||
$transaksi->{"uang_keluar$i"} ?? 0,
|
||||
$pendapatan,
|
||||
$beban
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hitung total
|
||||
$total_pendapatan = array_sum(array_column($pendapatan, 'nominal'));
|
||||
$total_beban = abs(array_sum(array_column($beban, 'nominal')));
|
||||
$laba_rugi = $total_pendapatan - $total_beban;
|
||||
|
||||
$html = '<!DOCTYPE html><html><head><title>Laporan Laba Rugi</title><style>
|
||||
body{font-family:Arial,sans-serif;font-size:12px;}
|
||||
table{width:100%;border-collapse:collapse;margin-bottom:20px;}
|
||||
table,th,td{border:1px solid #ddd;}
|
||||
th,td{padding:8px;text-align:left;}
|
||||
th{background-color:#6b46c1;color:white;}
|
||||
.bg-gray-100{background-color:#f3f4f6;}
|
||||
.bg-purple-100{background-color:#f3e8ff;}
|
||||
.text-right{text-align:right;}
|
||||
.font-bold{font-weight:bold;}
|
||||
.pl-8{padding-left:2rem;}
|
||||
</style></head><body>';
|
||||
|
||||
$html .= '<h2 style="text-align:center">Laporan Laba Rugi</h2>';
|
||||
$html .= '<p style="text-align:center">Periode: ' . date('F Y', strtotime($startDate)) . '</p>';
|
||||
|
||||
$html .= '<table>';
|
||||
|
||||
// Header
|
||||
$html .= '<tr><th>Keterangan</th><th style="text-align:right">Nominal</th></tr>';
|
||||
|
||||
// Pendapatan
|
||||
$html .= '<tr class="bg-gray-100"><td colspan="2" class="font-bold">Pendapatan</td></tr>';
|
||||
foreach ($pendapatan as $item) {
|
||||
$html .= '<tr>';
|
||||
$html .= '<td class="pl-8">' . ucwords($item['kategori']) . '</td>';
|
||||
$html .= '<td class="text-right">' . number_format(abs($item['nominal']), 0, ',', '.') . '</td>';
|
||||
$html .= '</tr>';
|
||||
}
|
||||
$html .= '<tr class="font-bold"><td>Total Pendapatan</td><td class="text-right">' . number_format(abs($total_pendapatan), 0, ',', '.') . '</td></tr>';
|
||||
|
||||
// Beban
|
||||
$html .= '<tr class="bg-gray-100"><td colspan="2" class="font-bold">Beban</td></tr>';
|
||||
foreach ($beban as $item) {
|
||||
$html .= '<tr>';
|
||||
$html .= '<td class="pl-8">' . ucwords($item['kategori']) . '</td>';
|
||||
$html .= '<td class="text-right">' . number_format(abs($item['nominal']), 0, ',', '.') . '</td>';
|
||||
$html .= '</tr>';
|
||||
}
|
||||
$html .= '<tr class="font-bold"><td>Total Beban</td><td class="text-right">' . number_format($total_beban, 0, ',', '.') . '</td></tr>';
|
||||
|
||||
// Laba/Rugi
|
||||
$html .= '<tr class="bg-purple-100"><td class="font-bold">Laba/Rugi Bersih</td><td class="text-right font-bold">';
|
||||
if ($laba_rugi < 0) {
|
||||
$html .= '-Rp ' . number_format(abs($laba_rugi), 0, ',', '.');
|
||||
} else {
|
||||
$html .= 'Rp ' . number_format($laba_rugi, 0, ',', '.');
|
||||
}
|
||||
$html .= '</td></tr>';
|
||||
|
||||
$html .= '</table></body></html>';
|
||||
|
||||
$pdf = \Barryvdh\DomPDF\Facade\Pdf::loadHTML($html);
|
||||
return $pdf->download('laporan-laba-rugi-'.date('Y-m-d').'.pdf');
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->back()->with('error', 'Gagal mengekspor PDF: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,54 +52,117 @@ public function filter(Request $request)
|
|||
return $this->index($request);
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
public function exportExcel(Request $request)
|
||||
{
|
||||
try {
|
||||
// Buat class export inline
|
||||
$export = new class implements FromCollection, WithHeadings, WithMapping {
|
||||
public function collection()
|
||||
{
|
||||
return LaporanModel::orderBy('Tanggal', 'desc')->get();
|
||||
$startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d'));
|
||||
$endDate = $request->input('end_date', Carbon::now()->endOfMonth()->format('Y-m-d'));
|
||||
$laporan = LaporanModel::whereBetween('Tanggal', [$startDate, $endDate])
|
||||
->orderBy('Tanggal', 'desc')
|
||||
->get();
|
||||
|
||||
$rows = [];
|
||||
$no = 1;
|
||||
$totalDebit = 0;
|
||||
$totalKredit = 0;
|
||||
|
||||
foreach ($laporan as $item) {
|
||||
// Cek apakah semua nilai adalah debit
|
||||
$allDebit = true;
|
||||
$debitValues = [
|
||||
$item->uang_masuk,
|
||||
$item->uang_masuk2,
|
||||
$item->uang_masuk3,
|
||||
$item->uang_masuk4,
|
||||
$item->uang_masuk5
|
||||
];
|
||||
|
||||
$validDebitValues = array_filter($debitValues, function($value) {
|
||||
return $value !== null && $value > 0;
|
||||
});
|
||||
|
||||
if ($item->uang_keluar > 0 ||
|
||||
($item->uang_keluar2 ?? 0) > 0 ||
|
||||
($item->uang_keluar3 ?? 0) > 0 ||
|
||||
($item->uang_keluar4 ?? 0) > 0 ||
|
||||
($item->uang_keluar5 ?? 0) > 0) {
|
||||
$allDebit = false;
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'ID',
|
||||
'Tanggal',
|
||||
'Kode',
|
||||
'Kategori',
|
||||
'Keterangan',
|
||||
'Uang Masuk',
|
||||
'Uang Keluar'
|
||||
// Proses data untuk setiap baris
|
||||
$rowDebit = 0;
|
||||
$rowKredit = 0;
|
||||
|
||||
if ($allDebit) {
|
||||
$lastDebitValue = end($validDebitValues);
|
||||
$firstDebitValue = reset($validDebitValues);
|
||||
|
||||
if (count($validDebitValues) > 1) {
|
||||
$rowDebit = $firstDebitValue;
|
||||
$rowKredit = $lastDebitValue;
|
||||
} else {
|
||||
$rowDebit = $firstDebitValue;
|
||||
$rowKredit = $firstDebitValue;
|
||||
}
|
||||
} else {
|
||||
$rowDebit = $item->uang_masuk +
|
||||
($item->uang_masuk2 ?? 0) +
|
||||
($item->uang_masuk3 ?? 0) +
|
||||
($item->uang_masuk4 ?? 0) +
|
||||
($item->uang_masuk5 ?? 0);
|
||||
|
||||
$rowKredit = $item->uang_keluar +
|
||||
($item->uang_keluar2 ?? 0) +
|
||||
($item->uang_keluar3 ?? 0) +
|
||||
($item->uang_keluar4 ?? 0) +
|
||||
($item->uang_keluar5 ?? 0);
|
||||
}
|
||||
|
||||
$totalDebit += $rowDebit;
|
||||
$totalKredit += $rowKredit;
|
||||
|
||||
// Gabungkan semua kode akun
|
||||
$kodeAkun = $item->kode;
|
||||
if (!empty($item->kode2)) $kodeAkun .= "\n" . $item->kode2;
|
||||
if (!empty($item->kode3)) $kodeAkun .= "\n" . $item->kode3;
|
||||
if (!empty($item->kode4)) $kodeAkun .= "\n" . $item->kode4;
|
||||
if (!empty($item->kode5)) $kodeAkun .= "\n" . $item->kode5;
|
||||
|
||||
// Gabungkan semua nama akun
|
||||
$namaAkun = $item->kategori;
|
||||
if (!empty($item->kategori2)) $namaAkun .= "\n" . $item->kategori2;
|
||||
if (!empty($item->kategori3)) $namaAkun .= "\n" . $item->kategori3;
|
||||
if (!empty($item->kategori4)) $namaAkun .= "\n" . $item->kategori4;
|
||||
if (!empty($item->kategori5)) $namaAkun .= "\n" . $item->kategori5;
|
||||
|
||||
$rows[] = [
|
||||
'No' => $no++,
|
||||
'Tanggal' => date('d/m/Y', strtotime($item->Tanggal)),
|
||||
'Kode Akun' => $kodeAkun,
|
||||
'Nama Akun' => $namaAkun,
|
||||
'Keterangan' => $item->keterangan . ' ' . $item->nama_karyawan,
|
||||
'Debit' => $rowDebit > 0 ? number_format($rowDebit, 0, ',', '.') : '-',
|
||||
'Kredit' => $rowKredit > 0 ? number_format($rowKredit, 0, ',', '.') : '-'
|
||||
];
|
||||
}
|
||||
|
||||
public function map($laporan): array
|
||||
{
|
||||
// Hitung total uang masuk untuk baris ini
|
||||
$totalUangMasuk = $laporan->uang_masuk +
|
||||
($laporan->uang_masuk2 ?? 0) +
|
||||
($laporan->uang_masuk3 ?? 0) +
|
||||
($laporan->uang_masuk4 ?? 0) +
|
||||
($laporan->uang_masuk5 ?? 0);
|
||||
|
||||
// Hitung total uang keluar untuk baris ini
|
||||
$totalUangKeluar = $laporan->uang_keluar +
|
||||
($laporan->uang_keluar2 ?? 0) +
|
||||
($laporan->uang_keluar3 ?? 0) +
|
||||
($laporan->uang_keluar4 ?? 0) +
|
||||
($laporan->uang_keluar5 ?? 0);
|
||||
|
||||
return [
|
||||
$laporan->id,
|
||||
$laporan->Tanggal,
|
||||
$laporan->kode,
|
||||
$laporan->kategori,
|
||||
$laporan->keterangan,
|
||||
$totalUangMasuk,
|
||||
$totalUangKeluar
|
||||
// Tambahkan baris total
|
||||
$rows[] = [
|
||||
'No' => '',
|
||||
'Tanggal' => '',
|
||||
'Kode Akun' => '',
|
||||
'Nama Akun' => '',
|
||||
'Keterangan' => 'Total',
|
||||
'Debit' => number_format($totalDebit, 0, ',', '.'),
|
||||
'Kredit' => number_format($totalKredit, 0, ',', '.')
|
||||
];
|
||||
|
||||
$export = new class($rows) implements FromCollection, WithHeadings {
|
||||
protected $rows;
|
||||
public function __construct($rows) { $this->rows = $rows; }
|
||||
public function collection() { return collect($this->rows); }
|
||||
public function headings(): array {
|
||||
return ['No', 'Tanggal', 'Kode Akun', 'Nama Akun', 'Keterangan', 'Debit', 'Kredit'];
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -109,131 +172,131 @@ public function map($laporan): array
|
|||
}
|
||||
}
|
||||
|
||||
public function exportPDF()
|
||||
public function exportPDF(Request $request)
|
||||
{
|
||||
try {
|
||||
$laporan = LaporanModel::orderBy('Tanggal', 'desc')->get();
|
||||
$startDate = $request->input('start_date', Carbon::now()->startOfMonth()->format('Y-m-d'));
|
||||
$endDate = $request->input('end_date', Carbon::now()->endOfMonth()->format('Y-m-d'));
|
||||
$laporan = LaporanModel::whereBetween('Tanggal', [$startDate, $endDate])
|
||||
->orderBy('Tanggal', 'desc')
|
||||
->get();
|
||||
|
||||
// Hitung total uang masuk
|
||||
$totalUangMasuk = LaporanModel::selectRaw('SUM(uang_masuk) +
|
||||
COALESCE(SUM(uang_masuk2), 0) +
|
||||
COALESCE(SUM(uang_masuk3), 0) +
|
||||
COALESCE(SUM(uang_masuk4), 0) +
|
||||
COALESCE(SUM(uang_masuk5), 0) as total')
|
||||
->value('total') ?? 0;
|
||||
$rows = '';
|
||||
$no = 1;
|
||||
$totalDebit = 0;
|
||||
$totalKredit = 0;
|
||||
|
||||
// Hitung total uang keluar
|
||||
$totalKredit = LaporanModel::selectRaw('SUM(uang_keluar) +
|
||||
COALESCE(SUM(uang_keluar2), 0) +
|
||||
COALESCE(SUM(uang_keluar3), 0) +
|
||||
COALESCE(SUM(uang_keluar4), 0) +
|
||||
COALESCE(SUM(uang_keluar5), 0) as total')
|
||||
->value('total') ?? 0;
|
||||
foreach ($laporan as $item) {
|
||||
// Cek apakah semua nilai adalah debit
|
||||
$allDebit = true;
|
||||
$debitValues = [
|
||||
$item->uang_masuk,
|
||||
$item->uang_masuk2,
|
||||
$item->uang_masuk3,
|
||||
$item->uang_masuk4,
|
||||
$item->uang_masuk5
|
||||
];
|
||||
|
||||
$saldo = $totalUangMasuk - $totalKredit;
|
||||
$validDebitValues = array_filter($debitValues, function($value) {
|
||||
return $value !== null && $value > 0;
|
||||
});
|
||||
|
||||
// Generate PDF
|
||||
$html = '
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Laporan Keuangan</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
if ($item->uang_keluar > 0 ||
|
||||
($item->uang_keluar2 ?? 0) > 0 ||
|
||||
($item->uang_keluar3 ?? 0) > 0 ||
|
||||
($item->uang_keluar4 ?? 0) > 0 ||
|
||||
($item->uang_keluar5 ?? 0) > 0) {
|
||||
$allDebit = false;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
table, th, td {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
th, td {
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
.summary {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.summary table {
|
||||
width: 300px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Laporan Keuangan</h2>
|
||||
<p>Tanggal: '.date('d-m-Y').'</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Kode</th>
|
||||
<th>Kategori</th>
|
||||
<th>Keterangan</th>
|
||||
<th>Uang Masuk</th>
|
||||
<th>Uang Keluar</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>';
|
||||
// Proses data untuk setiap baris
|
||||
$rowDebit = 0;
|
||||
$rowKredit = 0;
|
||||
|
||||
foreach($laporan as $index => $item) {
|
||||
// Hitung total uang masuk untuk baris ini
|
||||
$rowUangMasuk = $item->uang_masuk +
|
||||
if ($allDebit) {
|
||||
$lastDebitValue = end($validDebitValues);
|
||||
$firstDebitValue = reset($validDebitValues);
|
||||
|
||||
if (count($validDebitValues) > 1) {
|
||||
$rowDebit = $firstDebitValue;
|
||||
$rowKredit = $lastDebitValue;
|
||||
} else {
|
||||
$rowDebit = $firstDebitValue;
|
||||
$rowKredit = $firstDebitValue;
|
||||
}
|
||||
} else {
|
||||
$rowDebit = $item->uang_masuk +
|
||||
($item->uang_masuk2 ?? 0) +
|
||||
($item->uang_masuk3 ?? 0) +
|
||||
($item->uang_masuk4 ?? 0) +
|
||||
($item->uang_masuk5 ?? 0);
|
||||
|
||||
// Hitung total uang keluar untuk baris ini
|
||||
$rowUangKeluar = $item->uang_keluar +
|
||||
$rowKredit = $item->uang_keluar +
|
||||
($item->uang_keluar2 ?? 0) +
|
||||
($item->uang_keluar3 ?? 0) +
|
||||
($item->uang_keluar4 ?? 0) +
|
||||
($item->uang_keluar5 ?? 0);
|
||||
|
||||
$html .= '
|
||||
<tr>
|
||||
<td>'.($index + 1).'</td>
|
||||
<td>'.$item->Tanggal.'</td>
|
||||
<td>'.$item->kode.'</td>
|
||||
<td>'.$item->kategori.'</td>
|
||||
<td>'.$item->keterangan.'</td>
|
||||
<td>Rp '.number_format($rowUangMasuk, 0, ',', '.').'</td>
|
||||
<td>Rp '.number_format($rowUangKeluar, 0, ',', '.').'</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
$html .= '
|
||||
</tbody>
|
||||
</table>
|
||||
$totalDebit += $rowDebit;
|
||||
$totalKredit += $rowKredit;
|
||||
|
||||
<div class="summary">
|
||||
<h3>Ringkasan</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td><strong>Total Uang Masuk</strong></td>
|
||||
<td>Rp '.number_format($totalUangMasuk, 0, ',', '.').'</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Total Uang Keluar</strong></td>
|
||||
<td>Rp '.number_format($totalKredit, 0, ',', '.').'</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Saldo</strong></td>
|
||||
<td>Rp '.number_format($saldo, 0, ',', '.').'</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>';
|
||||
// Gabungkan semua kode akun
|
||||
$kodeAkun = $item->kode;
|
||||
if (!empty($item->kode2)) $kodeAkun .= "<br>" . $item->kode2;
|
||||
if (!empty($item->kode3)) $kodeAkun .= "<br>" . $item->kode3;
|
||||
if (!empty($item->kode4)) $kodeAkun .= "<br>" . $item->kode4;
|
||||
if (!empty($item->kode5)) $kodeAkun .= "<br>" . $item->kode5;
|
||||
|
||||
// Gabungkan semua nama akun
|
||||
$namaAkun = $item->kategori;
|
||||
if (!empty($item->kategori2)) $namaAkun .= "<br>" . $item->kategori2;
|
||||
if (!empty($item->kategori3)) $namaAkun .= "<br>" . $item->kategori3;
|
||||
if (!empty($item->kategori4)) $namaAkun .= "<br>" . $item->kategori4;
|
||||
if (!empty($item->kategori5)) $namaAkun .= "<br>" . $item->kategori5;
|
||||
|
||||
$rows .= '<tr>';
|
||||
$rows .= '<td style="text-align:center">'.$no++.'</td>';
|
||||
$rows .= '<td>'.date('d/m/Y', strtotime($item->Tanggal)).'</td>';
|
||||
$rows .= '<td>'.$kodeAkun.'</td>';
|
||||
$rows .= '<td>'.$namaAkun.'</td>';
|
||||
$rows .= '<td>'.$item->keterangan.' '.$item->nama_karyawan.'</td>';
|
||||
$rows .= '<td style="text-align:right">'.($rowDebit > 0 ? number_format($rowDebit, 0, ',', '.') : '-').'</td>';
|
||||
$rows .= '<td style="text-align:right">'.($rowKredit > 0 ? number_format($rowKredit, 0, ',', '.') : '-').'</td>';
|
||||
$rows .= '</tr>';
|
||||
}
|
||||
|
||||
// Tambahkan baris total
|
||||
$rows .= '<tr style="font-weight:bold;background-color:#f9f9f9;">';
|
||||
$rows .= '<td colspan="5" style="text-align:right">Total</td>';
|
||||
$rows .= '<td style="text-align:right">'.number_format($totalDebit, 0, ',', '.').'</td>';
|
||||
$rows .= '<td style="text-align:right">'.number_format($totalKredit, 0, ',', '.').'</td>';
|
||||
$rows .= '</tr>';
|
||||
|
||||
$html = '<!DOCTYPE html><html><head><title>Laporan Keuangan</title><style>
|
||||
body{font-family:Arial,sans-serif;font-size:12px;}
|
||||
table{width:100%;border-collapse:collapse;margin-bottom:20px;}
|
||||
table,th,td{border:1px solid #ddd;}
|
||||
th,td{padding:8px;text-align:left;}
|
||||
th{background-color:#f2f2f2;}
|
||||
tfoot td{font-weight:bold;background-color:#f9f9f9;}
|
||||
.text-right{text-align:right;}
|
||||
.text-center{text-align:center;}
|
||||
td{vertical-align:top;}
|
||||
</style></head><body>';
|
||||
$html .= '<h2 style="text-align:center">Laporan Keuangan</h2>';
|
||||
$html .= '<p style="text-align:center">Periode: '.date('d/m/Y', strtotime($startDate)).' - '.date('d/m/Y', strtotime($endDate)).'</p>';
|
||||
$html .= '<table><thead><tr>
|
||||
<th style="text-align:center">No</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Kode Akun</th>
|
||||
<th>Nama Akun</th>
|
||||
<th>Keterangan</th>
|
||||
<th style="text-align:right">Debit</th>
|
||||
<th style="text-align:right">Kredit</th>
|
||||
</tr></thead><tbody>';
|
||||
$html .= $rows;
|
||||
$html .= '</tbody></table></body></html>';
|
||||
|
||||
$pdf = PDF::loadHTML($html);
|
||||
return $pdf->download('laporan-keuangan-'.date('Y-m-d').'.pdf');
|
||||
|
|
|
@ -62,10 +62,9 @@ public function store(Request $request)
|
|||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => $validator->errors()->first()
|
||||
], 422);
|
||||
return redirect()->back()
|
||||
->with('error', $validator->errors()->first())
|
||||
->withInput();
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -76,22 +75,24 @@ public function store(Request $request)
|
|||
'tipe_pengguna' => $request->tipe_pengguna
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'User berhasil ditambahkan'
|
||||
]);
|
||||
return redirect()->route('User.index')
|
||||
->with('success', 'User berhasil ditambahkan!');
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Gagal menambahkan user: ' . $e->getMessage()
|
||||
], 500);
|
||||
return redirect()->back()
|
||||
->with('error', 'Gagal menambahkan user: ' . $e->getMessage())
|
||||
->withInput();
|
||||
}
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
try {
|
||||
$user = User::findOrFail($id);
|
||||
return view('EditAkun', compact('user'));
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->route('User.index')
|
||||
->with('error', 'User tidak ditemukan');
|
||||
}
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
|
@ -104,10 +105,9 @@ public function update(Request $request, $id)
|
|||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => $validator->errors()->first()
|
||||
], 422);
|
||||
return redirect()->back()
|
||||
->with('error', $validator->errors()->first())
|
||||
->withInput();
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -125,15 +125,12 @@ public function update(Request $request, $id)
|
|||
|
||||
$user->update($data);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'User berhasil diperbarui'
|
||||
]);
|
||||
return redirect()->route('User.index')
|
||||
->with('success', 'Data user berhasil diperbarui!');
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Gagal memperbarui user: ' . $e->getMessage()
|
||||
], 500);
|
||||
return redirect()->back()
|
||||
->with('error', 'Gagal memperbarui user: ' . $e->getMessage())
|
||||
->withInput();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,7 +142,7 @@ public function destroy($id)
|
|||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'User berhasil dihapus'
|
||||
'message' => 'User berhasil dihapus!'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
@extends('Core.Sidebar')
|
||||
|
||||
@section('content')
|
||||
<!-- Chart.js -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0"></script>
|
||||
|
||||
<style>
|
||||
.chart-container {
|
||||
position: relative;
|
||||
|
@ -192,20 +196,130 @@
|
|||
<!-- Charts Section -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
||||
<!-- Bar Chart -->
|
||||
<div class="bg-white p-6 rounded-xl shadow-sm">
|
||||
<h4 class="text-lg font-semibold text-gray-700 mb-4">Tren Pendapatan & Beban</h4>
|
||||
<div class="max-w-sm w-full bg-white rounded-lg shadow-sm dark:bg-gray-800 p-4 md:p-6">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<h5 class="leading-none text-3xl font-bold text-gray-900 dark:text-white pb-2">
|
||||
@if($labaRugiTotal < 0)
|
||||
-Rp {{ number_format(abs($labaRugiTotal), 0, ',', '.') }}
|
||||
@else
|
||||
Rp {{ number_format($labaRugiTotal, 0, ',', '.') }}
|
||||
@endif
|
||||
</h5>
|
||||
<p class="text-base font-normal text-gray-500 dark:text-gray-400">Laba/Rugi Total</p>
|
||||
</div>
|
||||
<div class="flex items-center px-2.5 py-0.5 text-base font-semibold {{ $growthPercentage >= 0 ? 'text-green-500' : 'text-red-500' }} dark:text-green-500 text-center">
|
||||
{{ number_format($growthPercentage, 1) }}%
|
||||
<svg class="w-3 h-3 ms-1" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 14">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13V1m0 0L1 5m4-4 4 4"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<canvas id="financial-trend-chart"></canvas>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 items-center border-gray-200 border-t dark:border-gray-700 justify-between">
|
||||
<div class="flex justify-between items-center pt-5">
|
||||
<!-- Button -->
|
||||
<button
|
||||
id="dropdownDefaultButton"
|
||||
data-dropdown-toggle="lastDaysdropdown"
|
||||
data-dropdown-placement="bottom"
|
||||
class="text-sm font-medium text-gray-500 dark:text-gray-400 hover:text-gray-900 text-center inline-flex items-center dark:hover:text-white"
|
||||
type="button">
|
||||
{{ date('d/m/Y', strtotime($startDate)) }} - {{ date('d/m/Y', strtotime($endDate)) }}
|
||||
<svg class="w-2.5 m-2.5 ms-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
|
||||
</svg>
|
||||
</button>
|
||||
<!-- Dropdown menu -->
|
||||
<div id="lastDaysdropdown" class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-44 dark:bg-gray-700">
|
||||
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" aria-labelledby="dropdownDefaultButton">
|
||||
<li>
|
||||
<a href="{{ route('home.filter', ['start_date' => Carbon\Carbon::yesterday()->format('Y-m-d'), 'end_date' => Carbon\Carbon::yesterday()->format('Y-m-d')]) }}" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Kemarin</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('home.filter', ['start_date' => Carbon\Carbon::today()->format('Y-m-d'), 'end_date' => Carbon\Carbon::today()->format('Y-m-d')]) }}" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Hari Ini</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('home.filter', ['start_date' => Carbon\Carbon::now()->subDays(7)->format('Y-m-d'), 'end_date' => Carbon\Carbon::now()->format('Y-m-d')]) }}" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">7 Hari Terakhir</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('home.filter', ['start_date' => Carbon\Carbon::now()->subDays(30)->format('Y-m-d'), 'end_date' => Carbon\Carbon::now()->format('Y-m-d')]) }}" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">30 Hari Terakhir</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('home.filter', ['start_date' => Carbon\Carbon::now()->subDays(90)->format('Y-m-d'), 'end_date' => Carbon\Carbon::now()->format('Y-m-d')]) }}" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">90 Hari Terakhir</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<button onclick="updateChartType('line')" class="text-sm font-medium text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white px-3 py-1 rounded-lg bg-gray-100 dark:bg-gray-700">Garis</button>
|
||||
<button onclick="updateChartType('bar')" class="text-sm font-medium text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white px-3 py-1 rounded-lg">Bar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Category Chart -->
|
||||
<div class="bg-white p-6 rounded-xl shadow-sm">
|
||||
<h4 class="text-lg font-semibold text-gray-700 mb-4">Distribusi per Kategori</h4>
|
||||
<div class="chart-container">
|
||||
<div class="max-w-sm w-full bg-white rounded-lg shadow-sm dark:bg-gray-800 p-4 md:p-6">
|
||||
<div class="flex flex-col w-full">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center">
|
||||
<h5 class="text-xl font-bold leading-none text-gray-900 dark:text-white">Distribusi Neraca Saldo</h5>
|
||||
<svg data-popover-target="chart-info" data-popover-placement="bottom" class="w-3.5 h-3.5 text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white cursor-pointer ms-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm0 16a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm1-5.034V12a1 1 0 0 1-2 0v-1.418a1 1 0 0 1 1.038-.999 1.436 1.436 0 0 0 1.488-1.441 1.501 1.501 0 1 0-3-.116.986.986 0 0 1-1.037.961 1 1 0 0 1-.96-1.037A3.5 3.5 0 1 1 11 11.466Z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<button id="dateRangeButton" data-dropdown-toggle="dateRangeDropdown" data-dropdown-ignore-click-outside-class="datepicker" type="button" class="inline-flex items-center text-blue-700 dark:text-blue-600 font-medium hover:underline">
|
||||
{{ date('d M', strtotime($startDate)) }} - {{ date('d M', strtotime($endDate)) }}
|
||||
<svg class="w-3 h-3 ms-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-col items-center justify-center py-4">
|
||||
<div class="chart-container" style="height: 260px; width: 260px;">
|
||||
<canvas id="category-distribution-chart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap justify-center gap-4 mt-4">
|
||||
@php
|
||||
$pieColors = ['#FF5733','#33FF57','#3357FF','#FF33A1','#FFBD33','#10b981','#f472b6','#6366f1','#f59e42','#e11d48'];
|
||||
@endphp
|
||||
@foreach($pieLabels as $i => $label)
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="w-3 h-3 rounded-full" style="background: {{ $pieColors[$i % count($pieColors)] }}"></span>
|
||||
<span class="text-sm">{{ $label }}</span>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="flex justify-between items-center border-t border-gray-200 dark:border-gray-700 mt-6 pt-4">
|
||||
<div class="flex items-center">
|
||||
<button id="dropdownDefaultButton" data-dropdown-toggle="lastDaysdropdown" data-dropdown-placement="bottom" class="text-sm font-medium text-gray-500 dark:text-gray-400 hover:text-gray-900 text-center inline-flex items-center dark:hover:text-white" type="button">
|
||||
Last 7 days
|
||||
<svg class="w-2.5 m-2.5 ms-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
|
||||
</svg>
|
||||
</button>
|
||||
<div id="lastDaysdropdown" class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-44 dark:bg-gray-700">
|
||||
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" aria-labelledby="dropdownDefaultButton">
|
||||
<li><a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Kemarin</a></li>
|
||||
<li><a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Hari Ini</a></li>
|
||||
<li><a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">7 Hari Terakhir</a></li>
|
||||
<li><a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">30 Hari Terakhir</a></li>
|
||||
<li><a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">90 Hari Terakhir</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#" class="uppercase text-sm font-semibold inline-flex items-center rounded-lg text-blue-600 hover:text-blue-700 dark:hover:text-blue-500 hover:bg-gray-100 dark:hover:bg-gray-700 dark:focus:ring-gray-700 dark:border-gray-700 px-3 py-2">
|
||||
LAPORAN KATEGORI
|
||||
<svg class="w-2.5 h-2.5 ms-1.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 9 4-4-4-4"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Transactions Table -->
|
||||
|
@ -254,11 +368,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<!-- Chart.js -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js"></script>
|
||||
<script>
|
||||
// Debugging untuk memastikan script berjalan
|
||||
console.log('Script started');
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('DOM Content Loaded');
|
||||
|
||||
// Format number to Rupiah
|
||||
function formatRupiah(number) {
|
||||
return 'Rp ' + number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
||||
|
@ -270,39 +386,36 @@ function formatRupiah(number) {
|
|||
if (trendCtx) {
|
||||
const monthlyData = @json($monthlyTotals);
|
||||
const labels = monthlyData.map(item => {
|
||||
const [year, month] = item.periode.split('-');
|
||||
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Ags', 'Sep', 'Okt', 'Nov', 'Des'];
|
||||
return `${monthNames[parseInt(month)-1]} ${year}`;
|
||||
const date = new Date(item.periode);
|
||||
return date.toLocaleDateString('id-ID', { day: 'numeric', month: 'short' });
|
||||
});
|
||||
const pendapatanData = monthlyData.map(item => parseFloat(item.total_debit) || 0);
|
||||
const bebanData = monthlyData.map(item => parseFloat(item.total_kredit) || 0);
|
||||
|
||||
new Chart(trendCtx, {
|
||||
type: 'bar',
|
||||
// Create gradient for area fill
|
||||
const gradientFill = trendCtx.getContext('2d').createLinearGradient(0, 0, 0, 400);
|
||||
gradientFill.addColorStop(0, 'rgba(34, 197, 94, 0.2)');
|
||||
gradientFill.addColorStop(1, 'rgba(34, 197, 94, 0)');
|
||||
|
||||
window.trendChart = new Chart(trendCtx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Pendapatan',
|
||||
data: pendapatanData,
|
||||
backgroundColor: 'rgba(34, 197, 94, 0.5)',
|
||||
borderColor: 'rgb(34, 197, 94)',
|
||||
borderWidth: 1,
|
||||
order: 2
|
||||
}, {
|
||||
label: 'Beban',
|
||||
data: bebanData,
|
||||
backgroundColor: 'rgba(239, 68, 68, 0.5)',
|
||||
borderColor: 'rgb(239, 68, 68)',
|
||||
borderWidth: 1,
|
||||
order: 2
|
||||
}, {
|
||||
label: 'Laba/Rugi',
|
||||
data: pendapatanData.map((pendapatan, index) => pendapatan - bebanData[index]),
|
||||
type: 'line',
|
||||
borderColor: 'rgb(59, 130, 246)',
|
||||
backgroundColor: gradientFill,
|
||||
fill: true,
|
||||
tension: 0.4,
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
order: 1
|
||||
pointRadius: 0,
|
||||
pointHoverRadius: 5,
|
||||
pointHoverBackgroundColor: 'rgb(34, 197, 94)',
|
||||
pointHoverBorderColor: '#fff',
|
||||
pointHoverBorderWidth: 2,
|
||||
cubicInterpolationMode: 'monotone',
|
||||
stepped: false
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
|
@ -312,89 +425,127 @@ function formatRupiah(number) {
|
|||
intersect: false,
|
||||
mode: 'index'
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return formatRupiah(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
return context.dataset.label + ': ' + formatRupiah(context.parsed.y);
|
||||
const value = context.parsed.y;
|
||||
return formatRupiah(value);
|
||||
},
|
||||
title: function(context) {
|
||||
return `Tanggal: ${context[0].label}`;
|
||||
}
|
||||
},
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
||||
padding: 12,
|
||||
titleFont: {
|
||||
size: 14,
|
||||
weight: 'bold'
|
||||
},
|
||||
bodyFont: {
|
||||
size: 13
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
grid: {
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
display: false
|
||||
}
|
||||
},
|
||||
x: {
|
||||
grid: {
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
font: {
|
||||
size: 11
|
||||
},
|
||||
maxRotation: 0,
|
||||
autoSkip: true,
|
||||
maxTicksLimit: 7
|
||||
}
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
tension: 0.4
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Debug untuk memastikan data terisi
|
||||
console.log('Chart Data:', {
|
||||
labels: labels,
|
||||
data: pendapatanData
|
||||
});
|
||||
}
|
||||
|
||||
// Category Distribution Chart
|
||||
const categoryCtx = document.getElementById('category-distribution-chart');
|
||||
if (categoryCtx) {
|
||||
const categoryData = @json($categoryTotals);
|
||||
const categories = categoryData.map(item => item.kategori);
|
||||
const pendapatanPerKategori = categoryData.map(item => parseFloat(item.total_debit) || 0);
|
||||
const bebanPerKategori = categoryData.map(item => parseFloat(item.total_kredit) || 0);
|
||||
|
||||
new Chart(categoryCtx, {
|
||||
type: 'bar',
|
||||
// Pie Chart Neraca Saldo
|
||||
var ctx = document.getElementById('category-distribution-chart').getContext('2d');
|
||||
var pieLabels = @json($pieLabels);
|
||||
var pieData = @json($pieData);
|
||||
var pieColors = [
|
||||
'#FF5733','#33FF57','#3357FF','#FF33A1','#FFBD33','#10b981','#f472b6','#6366f1','#f59e42','#e11d48'
|
||||
];
|
||||
var total = pieData.reduce((a, b) => a + b, 0);
|
||||
var myPieChart = new Chart(ctx, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: categories,
|
||||
labels: pieLabels,
|
||||
datasets: [{
|
||||
label: 'Pendapatan',
|
||||
data: pendapatanPerKategori,
|
||||
backgroundColor: 'rgba(34, 197, 94, 0.5)',
|
||||
borderColor: 'rgb(34, 197, 94)',
|
||||
borderWidth: 1
|
||||
}, {
|
||||
label: 'Beban',
|
||||
data: bebanPerKategori,
|
||||
backgroundColor: 'rgba(239, 68, 68, 0.5)',
|
||||
borderColor: 'rgb(239, 68, 68)',
|
||||
borderWidth: 1
|
||||
data: pieData,
|
||||
backgroundColor: pieColors,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
indexAxis: 'y',
|
||||
scales: {
|
||||
x: {
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return formatRupiah(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'bottom'
|
||||
legend: { display: false },
|
||||
datalabels: {
|
||||
color: '#fff',
|
||||
font: { weight: 'bold', size: 16 },
|
||||
formatter: function(value) {
|
||||
var percent = total ? (value / total * 100) : 0;
|
||||
return percent.toFixed(1) + '%';
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
return context.dataset.label + ': ' + formatRupiah(context.parsed.x);
|
||||
}
|
||||
var label = context.label || '';
|
||||
var value = context.parsed || 0;
|
||||
var percent = total ? (value / total * 100) : 0;
|
||||
return label + ': ' + value.toLocaleString('id-ID', {style:'currency', currency:'IDR'}) + ' (' + percent.toFixed(1) + '%)';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [ChartDataLabels]
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating charts:', error);
|
||||
}
|
||||
});
|
||||
|
||||
// Function to update chart type
|
||||
function updateChartType(type) {
|
||||
if (window.trendChart) {
|
||||
window.trendChart.config.type = type;
|
||||
window.trendChart.update();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@endsection
|
|
@ -60,7 +60,7 @@
|
|||
</tr>
|
||||
@foreach($pendapatan as $item)
|
||||
<tr class="border-b border-gray-300">
|
||||
<td class="p-2 border border-gray-300 pl-8">{{ ucwords($item['kategori']) }} ({{ $item['kode_akun'] }})</td>
|
||||
<td class="p-2 border border-gray-300 pl-8">{{ ucwords($item['kategori']) }}</td>
|
||||
<td class="text-right p-2 border border-gray-300">
|
||||
{{ number_format(abs($item['nominal']), 0, ',', '.') }}
|
||||
</td>
|
||||
|
@ -77,7 +77,7 @@
|
|||
</tr>
|
||||
@foreach($beban as $item)
|
||||
<tr class="border-b border-gray-300">
|
||||
<td class="p-2 border border-gray-300 pl-8">{{ ucwords($item['kategori']) }} ({{ $item['kode_akun'] }})</td>
|
||||
<td class="p-2 border border-gray-300 pl-8">{{ ucwords($item['kategori']) }}</td>
|
||||
<td class="text-right p-2 border border-gray-300">
|
||||
{{ number_format(abs($item['nominal']), 0, ',', '.') }}
|
||||
</td>
|
||||
|
@ -104,6 +104,84 @@
|
|||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex justify-between items-center mt-4 mb-4">
|
||||
<div class="flex space-x-2">
|
||||
<a href="{{ route('labarugi.export-excel', ['start_date' => $startDate, 'end_date' => $endDate]) }}" class="btn bg-green-500 text-white hover:bg-green-600 px-4 py-2 rounded">
|
||||
<i class="fas fa-file-excel mr-2"></i>Export Excel
|
||||
</a>
|
||||
<a href="{{ route('labarugi.export-pdf', ['start_date' => $startDate, 'end_date' => $endDate]) }}" class="btn bg-red-500 text-white hover:bg-red-600 px-4 py-2 rounded">
|
||||
<i class="fas fa-file-pdf mr-2"></i>Export PDF
|
||||
</a>
|
||||
<button onclick="window.print()" class="btn bg-gray-500 text-white hover:bg-gray-600 px-4 py-2 rounded">
|
||||
<i class="fas fa-print mr-2"></i>Print
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Style untuk print -->
|
||||
<style>
|
||||
@media print {
|
||||
.btn, header, footer, .no-print, nav, .aside {
|
||||
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;
|
||||
}
|
||||
table, th, td {
|
||||
border: 1px solid #000 !important;
|
||||
}
|
||||
th {
|
||||
background-color: #6b46c1 !important;
|
||||
color: white !important;
|
||||
-webkit-print-color-adjust: exact;
|
||||
color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
.text-right {
|
||||
text-align: right !important;
|
||||
}
|
||||
.bg-purple-100 {
|
||||
background-color: #f3e8ff !important;
|
||||
-webkit-print-color-adjust: exact;
|
||||
color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
.bg-gray-100 {
|
||||
background-color: #f3f4f6 !important;
|
||||
-webkit-print-color-adjust: exact;
|
||||
color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
<th class="py-3 px-4 text-left">Keterangan</th>
|
||||
<th class="py-3 px-4 text-right">Debit</th>
|
||||
<th class="py-3 px-4 text-right">Kredit</th>
|
||||
<th class="py-3 px-4 text-center">Aksi</th>
|
||||
<th class="py-3 px-4 text-center aksi-col">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tableBody">
|
||||
|
@ -310,7 +310,7 @@
|
|||
@endif
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-center">
|
||||
<td class="py-3 px-4 text-center aksi-col">
|
||||
<div class="flex justify-center space-x-2">
|
||||
<!-- <button class="text-blue-600 hover:text-blue-800" title="Edit">
|
||||
<i class="fas fa-edit"></i> -->
|
||||
|
@ -453,6 +453,9 @@
|
|||
.ml-8 {
|
||||
margin-left: 8px !important;
|
||||
}
|
||||
.aksi-col, .aksi-col * {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
<title>Login Page</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
|
||||
<!-- SweetAlert2 CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
||||
<!-- SweetAlert2 JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<style>
|
||||
body {
|
||||
background: linear-gradient(to bottom, #00c6ff, #0072ff, #ff00ff, #ff00ff);
|
||||
|
@ -14,21 +18,17 @@
|
|||
<body class="flex items-center justify-center min-h-screen">
|
||||
<div class="bg-white p-8 rounded-lg shadow-lg w-80">
|
||||
<h2 class="text-2xl font-bold text-center mb-6">Login</h2>
|
||||
@if(session('error'))
|
||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert">
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
<form method="POST" action="{{ route('login.authenticate') }}">
|
||||
<form method="POST" action="{{ route('login.authenticate') }}" id="loginForm">
|
||||
@csrf
|
||||
<div class="mb-4">
|
||||
<label class="block mb-2 text-sm font-medium text-gray-600" for="email">
|
||||
<i class="fas fa-user"></i> Email
|
||||
</label>
|
||||
<input class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
<input class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 @error('email') border-red-500 @enderror"
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
value="{{ old('email') }}"
|
||||
placeholder="Type your email"
|
||||
required>
|
||||
</div>
|
||||
|
@ -36,7 +36,7 @@
|
|||
<label class="block mb-2 text-sm font-medium text-gray-600" for="password">
|
||||
<i class="fas fa-lock"></i> Password
|
||||
</label>
|
||||
<input class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
<input class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 @error('password') border-red-500 @enderror"
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
|
@ -64,5 +64,33 @@
|
|||
</a>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
@if($errors->any())
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Oops...',
|
||||
text: '{{ $errors->first() }}',
|
||||
confirmButtonColor: '#3085d6',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
|
||||
@if(session('error'))
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Oops...',
|
||||
text: '{{ session("error") }}',
|
||||
confirmButtonColor: '#3085d6',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
</body>
|
||||
</html>
|
|
@ -163,6 +163,25 @@
|
|||
</div>
|
||||
|
||||
<script>
|
||||
// Notifikasi SweetAlert2
|
||||
@if(session('success'))
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil!',
|
||||
text: '{{ session("success") }}',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
@endif
|
||||
|
||||
@if(session('error'))
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal!',
|
||||
text: '{{ session("error") }}',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
@endif
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const userType = document.getElementById('userType');
|
||||
const searchUser = document.getElementById('searchUser');
|
||||
|
@ -208,41 +227,60 @@ function loadUsers(typeFilter = '', searchFilter = '') {
|
|||
})
|
||||
.catch(error => {
|
||||
console.error('Error loading users:', error);
|
||||
Swal.fire('Error!', 'Gagal memuat data user', 'error');
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error!',
|
||||
text: 'Gagal memuat data user',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function deleteUser(id) {
|
||||
Swal.fire({
|
||||
title: 'Hapus User',
|
||||
text: 'Apakah Anda yakin ingin menghapus user ini?',
|
||||
title: 'Apakah Anda yakin?',
|
||||
text: "Data yang dihapus tidak dapat dikembalikan!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Ya, Hapus',
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: 'Ya, hapus!',
|
||||
cancelButtonText: 'Batal'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
fetch(`/User/${id}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil!',
|
||||
text: 'Data user berhasil dihapus',
|
||||
confirmButtonText: 'OK'
|
||||
}).then(() => {
|
||||
loadUsers(
|
||||
document.getElementById('userType').value,
|
||||
document.getElementById('searchUser').value
|
||||
);
|
||||
Swal.fire('Berhasil!', 'User telah dihapus', 'success');
|
||||
});
|
||||
} else {
|
||||
throw new Error(data.message || 'Gagal menghapus user');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error deleting user:', error);
|
||||
Swal.fire('Error!', 'Gagal menghapus user', 'error');
|
||||
console.error('Error:', error);
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal!',
|
||||
text: error.message || 'Terjadi kesalahan saat menghapus data',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -84,4 +84,6 @@
|
|||
// Routes untuk Laba Rugi
|
||||
Route::get('/labarugi', [LabarugiController::class, 'index'])->name('labarugi.index');
|
||||
Route::get('/labarugi/filter', [LabarugiController::class, 'filter'])->name('labarugi.filter');
|
||||
Route::get('/labarugi/export-excel', [LabarugiController::class, 'exportExcel'])->name('labarugi.export-excel');
|
||||
Route::get('/labarugi/export-pdf', [LabarugiController::class, 'exportPDF'])->name('labarugi.export-pdf');
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue