feat(transactions): işlem formu, bölme, liste, filtreler, ayrıntı ve CSV

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-05 03:23:30 +03:00
parent 1208e2d1eb
commit dcfa2f8c8d
8 changed files with 1761 additions and 75 deletions
@@ -0,0 +1,44 @@
import { exportTransactions } from "@/features/transactions/service";
import { tr } from "@/i18n/tr";
import { getHouseholdContext } from "@/lib/dal";
import { csvMoney, toCsv } from "@/shared/csv";
import { todayIstanbul } from "@/shared/dates";
import { formatDate } from "@/shared/format";
import { transactionFilterSchema } from "@/shared/schemas/transaction";
/** GET /islemler/disa-aktar?…filtreler → CSV (listedeki filtrelerle, sayfalama yok). */
export async function GET(request: Request) {
const ctx = await getHouseholdContext();
if (!ctx?.household) return new Response(tr.common.unauthorized, { status: 401 });
const params = Object.fromEntries(new URL(request.url).searchParams);
const filters = transactionFilterSchema.parse(params);
const rows = await exportTransactions(ctx.user.id, ctx.household.id, filters);
if (!rows) return new Response(tr.common.unauthorized, { status: 403 });
const t = tr.transactions;
const csv = toCsv(
t.csv.header,
rows.map((r) => [
r.no,
formatDate(`${r.date}T12:00:00+03:00`),
t.types[r.type],
t.statuses[r.status],
r.account,
r.toAccount,
r.category,
r.payee,
r.description,
r.note,
r.tags,
csvMoney(r.amountMinor),
r.createdBy,
]),
);
return new Response(csv, {
headers: {
"Content-Type": "text/csv; charset=utf-8",
"Content-Disposition": `attachment; filename="${t.csv.filename(todayIstanbul())}"`,
"Cache-Control": "no-store",
},
});
}