bank-sampah/Controllers/Main/LaporanKeuanganController.cs

174 lines
6.0 KiB
C#

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<MonthlyTransactionSnapshot> _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<ManualExpense> _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<FinancialRow> BuildRows(int year)
{
var rows = new List<FinancialRow>();
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; }
}
}