feat(ui): Kakeibo grupları — kategori, işlem formu, rapor ve bütçe özeti
- kategori formunda grup ve banka maliyeti; listede grup rozeti ve grupsuz uyarısı - işlem formunda "Kategoriden: …" önerili grup seçimi, bölünmüş kalem başına - /raporlar/kakeibo (yığılmış pay çubuğu, grup kartları, banka maliyeti, grupsuzlar, CSV) - bütçe sayfasında Kakeibo özeti Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { csvContext, csvResponse, forbidden, unauthorized } from "@/features/reports/csv";
|
||||
import { getKakeiboReport } from "@/features/reports/kakeibo";
|
||||
import { tr } from "@/i18n/tr";
|
||||
import { csvMoney, toCsv } from "@/shared/csv";
|
||||
import { KAKEIBO_GROUPS, type SpendingClass } from "@/shared/kakeibo";
|
||||
|
||||
/** GET /raporlar/kakeibo/csv?ay=YYYY-MM — sınıf × kategori tutarları. */
|
||||
export async function GET(request: Request) {
|
||||
const c = await csvContext(request);
|
||||
if (!c) return unauthorized();
|
||||
const r = await getKakeiboReport(c.userId, c.householdId, c.month);
|
||||
if (!r) return forbidden();
|
||||
const k = tr.kakeibo;
|
||||
const label = (cls: SpendingClass) =>
|
||||
cls === "BANK_COST" ? k.bankCost : cls === "UNGROUPED" ? k.ungrouped : k.groups[cls];
|
||||
const order: SpendingClass[] = [...KAKEIBO_GROUPS, "UNGROUPED", "BANK_COST"];
|
||||
const rows = order.flatMap((cls) =>
|
||||
r.now.byClass[cls].map((x) => [label(cls), x.path, csvMoney(x.amountMinor)]),
|
||||
);
|
||||
return csvResponse(
|
||||
toCsv(tr.reports.kakeiboReport.csvHeader, rows),
|
||||
tr.reports.kakeiboReport.csvFile(r.month),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user