// routes/api/import/obligations.ts // Import obligations from JSON; skip items that already exist (by id or by content). import { define } from "../../../utils.ts"; import { createObligation, getObligationsByUser, } from "../../../services/financhalServices.ts"; import { SessionCookie } from "../../auth/callback.ts"; type ImportItem = { id?: string; description?: string | null; amount?: number | null; frequency?: string | null; due_date?: string | number | null; }; function signature(ob: { description?: string | null; amount?: number | null; frequency?: string | null; due_date?: number | null; }): string { const d = ob.due_date ?? 0; return `${ob.description ?? ""}|${ob.amount ?? 0}|${ob.frequency ?? ""}|${d}`; } export const handler = define.handlers({ async POST(ctx) { try { const stateData: SessionCookie = ctx.state.data; const user_id = stateData?.user_id; if (!user_id) { return new Response( JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "Content-Type": "application/json" } }, ); } const contentType = ctx.req.headers.get("content-type") ?? ""; if (!contentType.includes("application/json")) { return new Response( JSON.stringify({ error: "Content-Type must be application/json" }), { status: 400, headers: { "Content-Type": "application/json" } }, ); } const body = await ctx.req.json(); const raw = Array.isArray(body) ? body : body?.obligations; if (!Array.isArray(raw)) { return new Response( JSON.stringify({ error: "Body must be an array or { obligations: [] }", }), { status: 400, headers: { "Content-Type": "application/json" } }, ); } const existing = await getObligationsByUser(user_id); const existingIds = new Set(existing.map((o) => o.id)); const existingSigs = new Set( existing.map((o) => signature({ description: o.description, amount: o.amount, frequency: o.frequency, due_date: o.due_date, }) ), ); let added = 0; for (const item of raw as ImportItem[]) { const id = typeof item.id === "string" ? item.id : undefined; if (id && existingIds.has(id)) continue; const amount = item.amount != null ? Number(item.amount) : null; const dueDateRaw = item.due_date; let due_date: number; if (dueDateRaw == null || dueDateRaw === "") { due_date = 0; } else if (typeof dueDateRaw === "number") { due_date = dueDateRaw; } else { due_date = Date.parse(String(dueDateRaw).replace(/Z?$/, "T00:00:00")) || 0; } const desc = item.description != null ? String(item.description) : null; const freq = (item.frequency != null ? String(item.frequency) : "") || "monthly"; const sig = signature({ description: desc, amount, frequency: freq, due_date: due_date || undefined, }); if (existingSigs.has(sig)) continue; await createObligation( user_id, desc, amount != null && amount > 0 ? amount : null, freq, due_date, "", ); added++; existingSigs.add(sig); } return new Response( JSON.stringify({ added, total: raw.length, skipped: raw.length - added, }), { status: 200, headers: { "Content-Type": "application/json" } }, ); } catch (e) { console.error("Import obligations error:", e); return new Response( JSON.stringify({ error: "Failed to import obligations" }), { status: 500, headers: { "Content-Type": "application/json" } }, ); } }, });