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; } } }