"use server"; import { revalidatePath } from "next/cache"; import { z } from "zod"; import { tr } from "@/i18n/tr"; import { fail, ok, type ActionResult } from "@/lib/action-result"; import { getHouseholdActionContext } from "@/lib/dal"; import { reconcileSchema } from "@/shared/schemas/reconciliation"; import { transactionFormSchema } from "@/shared/schemas/transaction"; import { createTransaction, getTransaction, getTransactionFormOptions, searchPayees, setTransactionDeleted, updateTransaction, type PayeeSuggestion, type TransactionDetail, type TransactionFormOptions, } from "./service"; import { previewReconciliation, reconcileAccount, type ReconcilePreview } from "./statement"; const idSchema = z.string().regex(/^[a-f0-9]{24}$/i); /** zod hatalarını alan bazlı mesajlara çevirir ("splits.1.amount" gibi yollar korunur). */ function fieldErrors(error: z.ZodError) { const out: Record = {}; for (const issue of error.issues) { const key = issue.path.join("."); if (key && !out[key]) out[key] = issue.message; } return out; } function revalidate() { // Bakiye, liste ve (ileride) dashboard aynı veriden beslenir. revalidatePath("/", "layout"); } export async function createTransactionAction( input: unknown, ): Promise> { const ctx = await getHouseholdActionContext("member"); if (!ctx) return fail(tr.common.unauthorized); const parsed = transactionFormSchema.safeParse(input); if (!parsed.success) return fail(tr.adminUsers.errors.checkFields, fieldErrors(parsed.error)); const result = await createTransaction(ctx.user.id, ctx.household.id, parsed.data); if (result.ok) revalidate(); return result; } export async function updateTransactionAction( transactionId: unknown, input: unknown, ): Promise { const ctx = await getHouseholdActionContext("member"); if (!ctx) return fail(tr.common.unauthorized); const id = idSchema.safeParse(transactionId); if (!id.success) return fail(tr.common.notFound); const parsed = transactionFormSchema.safeParse(input); if (!parsed.success) return fail(tr.adminUsers.errors.checkFields, fieldErrors(parsed.error)); const result = await updateTransaction(ctx.user.id, ctx.household.id, id.data, parsed.data); if (result.ok) revalidate(); return result; } export async function setTransactionDeletedAction( transactionId: unknown, deleted: unknown, ): Promise { const ctx = await getHouseholdActionContext("member"); if (!ctx) return fail(tr.common.unauthorized); const id = idSchema.safeParse(transactionId); const d = z.boolean().safeParse(deleted); if (!id.success || !d.success) return fail(tr.common.genericError); const result = await setTransactionDeleted(ctx.user.id, ctx.household.id, id.data, d.data); if (result.ok) revalidate(); return result; } /** Form açılırken: yazılabilir hesaplar ve kategoriler (hızlı ekle her ekrandan çağırır). */ export async function getTransactionFormOptionsAction(): Promise< ActionResult > { const ctx = await getHouseholdActionContext("member"); if (!ctx) return fail(tr.common.unauthorized); const options = await getTransactionFormOptions(ctx.user.id, ctx.household.id); return options ? ok(options) : fail(tr.common.unauthorized); } export async function getTransactionAction( transactionId: unknown, ): Promise> { const ctx = await getHouseholdActionContext("viewer"); if (!ctx) return fail(tr.common.unauthorized); const id = idSchema.safeParse(transactionId); if (!id.success) return fail(tr.common.notFound); const detail = await getTransaction(ctx.user.id, ctx.household.id, id.data); return detail ? ok(detail) : fail(tr.common.notFound); } export async function searchPayeesAction(query: unknown): Promise { const ctx = await getHouseholdActionContext("member"); const q = z.string().max(80).safeParse(query); if (!ctx || !q.success) return []; return searchPayees(ctx.user.id, ctx.household.id, q.data); } /** Mutabakat önizlemesi: ekstre bakiyesi ile uygulama bakiyesi arasındaki fark. */ export async function previewReconciliationAction( accountId: unknown, input: unknown, ): Promise> { const ctx = await getHouseholdActionContext("member"); if (!ctx) return fail(tr.common.unauthorized); const id = idSchema.safeParse(accountId); if (!id.success) return fail(tr.common.notFound); const parsed = reconcileSchema.safeParse(input); if (!parsed.success) return fail(tr.adminUsers.errors.checkFields, fieldErrors(parsed.error)); return previewReconciliation(ctx.user.id, ctx.household.id, id.data, parsed.data); } export async function reconcileAccountAction( accountId: unknown, input: unknown, ): Promise> { const ctx = await getHouseholdActionContext("member"); if (!ctx) return fail(tr.common.unauthorized); const id = idSchema.safeParse(accountId); if (!id.success) return fail(tr.common.notFound); const parsed = reconcileSchema.safeParse(input); if (!parsed.success) return fail(tr.adminUsers.errors.checkFields, fieldErrors(parsed.error)); const result = await reconcileAccount(ctx.user.id, ctx.household.id, id.data, parsed.data); if (result.ok) revalidate(); return result; }