diff --git a/Controllers/Main/LaporanKeuanganController.cs b/Controllers/Main/LaporanKeuanganController.cs new file mode 100644 index 0000000..7622d45 --- /dev/null +++ b/Controllers/Main/LaporanKeuanganController.cs @@ -0,0 +1,173 @@ +using Microsoft.AspNetCore.Mvc; +using System.ComponentModel.DataAnnotations; +using System.Globalization; + +namespace BankSampahApp.Controllers.Main; + +[Route("Main/[controller]/[action]")] +public class LaporanKeuanganController : Controller +{ + private static readonly List _monthlyTransactions = + [ + new(2025, 1, 12_500_000m, 18_200_000m), + new(2025, 2, 10_350_000m, 16_750_000m), + new(2025, 3, 9_800_000m, 17_150_000m), + new(2025, 4, 11_200_000m, 15_600_000m), + new(2025, 5, 12_200_000m, 18_900_000m), + new(2025, 6, 10_450_000m, 14_800_000m), + new(2025, 7, 9_900_000m, 19_750_000m), + new(2025, 8, 11_650_000m, 17_500_000m), + new(2025, 9, 12_400_000m, 18_350_000m), + new(2024, 10, 10_050_000m, 15_500_000m), + new(2024, 11, 11_250_000m, 16_200_000m), + new(2024, 12, 12_800_000m, 18_600_000m) + ]; + + private static readonly List _manualExpenses = + [ + new() { Id = 1, ExpenseDate = new DateTime(2025, 1, 12), Title = "Transport & Operasional", Amount = 1_200_000m, Notes = "Pengiriman sampah ke offtaker" }, + new() { Id = 2, ExpenseDate = new DateTime(2025, 3, 8), Title = "Perawatan Timbangan", Amount = 800_000m, Notes = "Kalibrasi timbangan BSU" }, + new() { Id = 3, ExpenseDate = new DateTime(2025, 5, 20), Title = "Konsumsi Sosialisasi", Amount = 450_000m, Notes = "Kegiatan edukasi warga" }, + new() { Id = 4, ExpenseDate = new DateTime(2024, 11, 14), Title = "Biaya Listrik Gudang", Amount = 600_000m, Notes = "Tagihan bulan berjalan" } + ]; + + public IActionResult Index() + { + var years = _monthlyTransactions + .Select(t => t.Year) + .Concat(_manualExpenses.Select(e => e.ExpenseDate.Year)) + .Distinct() + .OrderByDescending(y => y) + .ToList(); + + if (!years.Any()) + { + years.Add(DateTime.UtcNow.Year); + } + + ViewBag.AvailableYears = years; + ViewBag.DefaultYear = years.First(); + return View("~/Views/Main/LaporanKeuangan/Index.cshtml"); + } + + [HttpGet] + public IActionResult Table(int? year) + { + var selectedYear = year ?? GetLatestYear(); + var rows = BuildRows(selectedYear); + var totalSaldo = rows.LastOrDefault()?.SaldoAkumulatif ?? 0m; + + var data = rows.Select((row, index) => new + { + no = index + 1, + bulan = row.Bulan, + pembelian = row.Pembelian, + penjualan = row.Penjualan, + pengeluaran = row.PengeluaranLain, + labaRugi = row.LabaRugiBulanan, + saldo = row.SaldoAkumulatif, + isProfit = row.LabaRugiBulanan >= 0 + }); + + return Json(new { data, totalSaldo }); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public IActionResult TambahPengeluaran([FromForm] PengeluaranInput input) + { + if (!ModelState.IsValid || input.Nominal <= 0) + { + return BadRequest(new { message = "Data pengeluaran tidak valid" }); + } + + var newExpense = new ManualExpense + { + Id = _manualExpenses.Any() ? _manualExpenses.Max(x => x.Id) + 1 : 1, + ExpenseDate = input.Tanggal, + Title = input.NamaPengeluaran, + Amount = input.Nominal, + Notes = input.Keterangan ?? string.Empty + }; + + _manualExpenses.Add(newExpense); + return Json(new { success = true }); + } + + private static List BuildRows(int year) + { + var rows = new List(); + var culture = new CultureInfo("id-ID"); + decimal saldoAkumulatif = 0m; + + for (int month = 1; month <= 12; month++) + { + var baseData = _monthlyTransactions.FirstOrDefault(t => t.Year == year && t.Month == month); + var pembelian = baseData?.Pembelian ?? 0m; + var penjualan = baseData?.Penjualan ?? 0m; + var pengeluaranLain = _manualExpenses + .Where(e => e.ExpenseDate.Year == year && e.ExpenseDate.Month == month) + .Sum(e => e.Amount); + + var labaRugi = penjualan - (pembelian + pengeluaranLain); + saldoAkumulatif += labaRugi; + + rows.Add(new FinancialRow + { + Bulan = culture.DateTimeFormat.GetMonthName(month) + " " + year, + Pembelian = pembelian, + Penjualan = penjualan, + PengeluaranLain = pengeluaranLain, + LabaRugiBulanan = labaRugi, + SaldoAkumulatif = saldoAkumulatif + }); + } + + return rows; + } + + private static int GetLatestYear() + { + return _monthlyTransactions.Select(t => t.Year) + .Concat(_manualExpenses.Select(e => e.ExpenseDate.Year)) + .DefaultIfEmpty(DateTime.UtcNow.Year) + .Max(); + } + + private record MonthlyTransactionSnapshot(int Year, int Month, decimal Pembelian, decimal Penjualan); + + private class ManualExpense + { + public int Id { get; set; } + public DateTime ExpenseDate { get; set; } + public string Title { get; set; } = string.Empty; + public decimal Amount { get; set; } + public string Notes { get; set; } = string.Empty; + } + + public class PengeluaranInput + { + [Required] + public DateTime Tanggal { get; set; } + + [Required] + [StringLength(150)] + public string NamaPengeluaran { get; set; } = string.Empty; + + [Range(typeof(decimal), "0.01", "79228162514264337593543950335")] + public decimal Nominal { get; set; } + + [StringLength(200)] + public string? Keterangan { get; set; } + } + + private class FinancialRow + { + public string Bulan { get; set; } = string.Empty; + public decimal Pembelian { get; set; } + public decimal Penjualan { get; set; } + public decimal PengeluaranLain { get; set; } + public decimal LabaRugiBulanan { get; set; } + public decimal SaldoAkumulatif { get; set; } + } +} diff --git a/Views/Main/LaporanKeuangan/Index.cshtml b/Views/Main/LaporanKeuangan/Index.cshtml new file mode 100644 index 0000000..f568668 --- /dev/null +++ b/Views/Main/LaporanKeuangan/Index.cshtml @@ -0,0 +1,287 @@ +@{ + ViewData["Title"] = "Laporan Keuangan"; +} + +
+
+ + Laporan Keuangan + +

Rekap otomatis pembelian, penjualan, dan pengeluaran BSU per bulan.

+
+ +
+ + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + +
NoBulanPembelian (Rp)Penjualan (Rp)Pengeluaran Lain-lain (Rp)Laba/Rugi Bulanan (Rp)Saldo Akumulatif (Rp)
+
+
+
+ +
+
+

Saldo akumulatif tahun berjalan

+

Rp 0

+
+
+ Data dihitung otomatis dari transaksi pembelian, penjualan, dan pengeluaran manual. +
+
+ + + + + + + + +@section Scripts { + +} diff --git a/Views/Shared/_SidebarUnified.cshtml b/Views/Shared/_SidebarUnified.cshtml index fc8a17c..c7e57dd 100644 --- a/Views/Shared/_SidebarUnified.cshtml +++ b/Views/Shared/_SidebarUnified.cshtml @@ -133,6 +133,14 @@ + +
  • + + + Laporan Keuangan + +
  • +