import type { Types } from "mongoose"; import { addContribution, createInKind, savePrice } from "@/features/in-kind/service"; import { AccountModel } from "@/models/account"; import { AssetPriceModel } from "@/models/asset-price"; import { ContactModel } from "@/models/contact"; import { InKindDebtModel } from "@/models/in-kind-debt"; import type { AssetKey } from "@/shared/assets"; import { todayIstanbul } from "@/shared/dates"; import { formatMoneyInput } from "@/shared/money"; import { addDays, addMonths } from "@/shared/recurrence"; import { assetPriceFormSchema, contributionSchema, inKindFormSchema, } from "@/shared/schemas/in-kind"; /** * Örnek fiyat tablosu ve aynî kayıtlar (Faz 8b). Fiyatlar örnek amaçlıdır (gerçek piyasa verisi * değildir): son 6 ay, ayda bir kayıt, doğrusal artış. İdempotent. */ /** [6 ay önceki alış, bugünkü alış, satış farkı] — birim başına kuruş. */ const PRICE_PATH: Partial> = { gram_gold: [4_900_00, 5_600_00, 100_00], quarter_gold: [8_050_00, 9_200_00, 250_00], usd: [40_20, 42_80, 30], eur: [46_90, 49_50, 40], }; async function seedPrices(householdId: Types.ObjectId, actorId: string, today: string) { for (const [k, [from, to, spread]] of Object.entries(PRICE_PATH)) { const key = k as AssetKey; for (let i = 6; i >= 0; i--) { const date = i === 0 ? today : addMonths(today, -i); if (await AssetPriceModel.exists({ householdId, assetKey: key, date })) continue; const buy = Math.round(to - ((to - from) * i) / 6); await savePrice( actorId, String(householdId), assetPriceFormSchema.parse({ assetKey: key, date, buy: formatMoneyInput(buy), sell: formatMoneyInput(buy + spread), }), ); } } } type SeedInKind = { ref: string; household: string; contact: string; by: string; direction: "debt" | "receivable"; assetKey: AssetKey; quantity: string; daysAgo: number; note?: string; savings?: string; monthlyPlanMinor?: number; contributions?: { from: string; amountMinor: number; daysAgo: number }[]; }; const ITEMS: SeedInKind[] = [ { ref: "hasan-altin", household: "Çakır Ailesi", contact: "contact:hasan", by: "admin", direction: "debt", assetKey: "gram_gold", quantity: "5", daysAgo: 95, note: "Düğün için ödünç alınan altın", savings: "Birikim (Vadeli)", monthlyPlanMinor: 4_000_00, contributions: [ { from: "Ziraat Maaş", amountMinor: 4_000_00, daysAgo: 60 }, { from: "Ziraat Maaş", amountMinor: 4_000_00, daysAgo: 30 }, ], }, { ref: "elif-usd", household: "Çakır Ailesi", contact: "contact:elif", by: "ayse", direction: "receivable", assetKey: "usd", quantity: "100", daysAgo: 40, }, { ref: "ali-ceyrek", household: "Annemler", contact: "contact:ali", by: "fatma", direction: "receivable", assetKey: "quarter_gold", quantity: "2", daysAgo: 150, note: "Torun doğumunda verilen çeyrekler", }, ]; export async function seedInKind( householdIds: Map, userIds: Map, ): Promise { const today = todayIstanbul(); await seedPrices(householdIds.get("Çakır Ailesi")!, userIds.get("admin")!, today); await seedPrices(householdIds.get("Annemler")!, userIds.get("fatma")!, today); let created = 0; for (const x of ITEMS) { const householdId = householdIds.get(x.household)!; const seedRef = `inkind:${x.ref}`; if (await InKindDebtModel.exists({ householdId, seedRef })) continue; const contact = await ContactModel.findOne({ householdId, seedRef: x.contact }).lean(); if (!contact) continue; const account = async (name: string) => String((await AccountModel.findOne({ householdId, name }).lean())!._id); const by = userIds.get(x.by)!; const r = await createInKind( by, String(householdId), String(contact._id), inKindFormSchema.parse({ direction: x.direction, assetKey: x.assetKey, quantity: x.quantity, date: addDays(today, -x.daysAgo), note: x.note ?? "", savingsAccountId: x.savings ? await account(x.savings) : "", monthlyPlan: x.monthlyPlanMinor ? formatMoneyInput(x.monthlyPlanMinor) : "", }), ); if (!r.ok) throw new Error(`Seed aynî kaydı oluşturulamadı (${x.ref}): ${r.error}`); await InKindDebtModel.updateOne({ _id: r.data.id }, { $set: { seedRef } }); for (const c of x.contributions ?? []) { const res = await addContribution( by, String(householdId), r.data.id, contributionSchema.parse({ fromAccountId: await account(c.from), amount: formatMoneyInput(c.amountMinor), date: addDays(today, -c.daysAgo), }), ); if (!res.ok) throw new Error(`Seed birikimi oluşturulamadı (${x.ref}): ${res.error}`); } created++; } return created; }