import type { Types } from "mongoose"; import { addMovement, createAsset } from "@/features/assets/service"; import { AccountModel } from "@/models/account"; import { AssetModel } from "@/models/asset"; import { AssetMovementModel } from "@/models/asset-movement"; import { TransactionModel } from "@/models/transaction"; import type { AssetKey } from "@/shared/assets"; import { todayIstanbul } from "@/shared/dates"; import type { MovementKind } from "@/shared/portfolio"; import { addDays } from "@/shared/recurrence"; import { assetFormSchema, movementFormSchema } from "@/shared/schemas/asset"; /** * Örnek varlıklar (Faz 9a). Tutarı boş alımlar fiyat tablosundaki örnek fiyatlardan (seedInKind * önce çalışır) hesaplanır. İdempotent: varlık `seedRef` ile bir kez oluşturulur. */ type SeedMovement = { kind: MovementKind; daysAgo: number; quantity: string; amount?: string; account?: string; storage?: string; note?: string; }; type SeedAsset = { ref: string; household: string; by: string; assetKey: AssetKey; name: string; isPrivate?: boolean; note?: string; movements: SeedMovement[]; }; const monthly = (from: number, to: number): SeedMovement[] => Array.from({ length: to - from + 1 }, (_, i) => ({ kind: "buy" as const, daysAgo: (to - i) * 30 + 2, quantity: "1", account: "Ziraat Maaş", storage: "Ev kasası", })); const ITEMS: SeedAsset[] = [ { ref: "gram-altin", household: "Çakır Ailesi", by: "ayse", assetKey: "gram_gold", name: "Gram altın birikimi", note: "Her ay maaştan 1 gr", movements: [ { kind: "buy", daysAgo: 178, quantity: "4", account: "Birikim (Vadeli)", storage: "Ev kasası", note: "İlk alım", }, ...monthly(1, 5), { kind: "sell", daysAgo: 12, quantity: "2", account: "Birikim (Vadeli)", note: "Tatil için" }, ], }, { ref: "ziynet", household: "Çakır Ailesi", by: "admin", assetKey: "quarter_gold", name: "Düğün ziynetleri", movements: [ { kind: "gift_in", daysAgo: 175, quantity: "6", storage: "Banka kiralık kasa", note: "Düğün takıları", }, { kind: "gift_out", daysAgo: 40, quantity: "1", note: "Yeğenin düğünü" }, ], }, { ref: "emre-dolar", household: "Çakır Ailesi", by: "emre", assetKey: "usd", name: "Dolar", isPrivate: true, movements: [ { kind: "buy", daysAgo: 120, quantity: "200", account: "Ziraat Maaş", storage: "Cüzdan" }, ], }, { ref: "bilezik", household: "Annemler", by: "fatma", assetKey: "bracelet_22k", name: "Bilezikler", note: "Fiyat tablosunda bilezik fiyatı yok (örnek: fiyatsız varlık)", movements: [{ kind: "gift_in", daysAgo: 160, quantity: "40", amount: "120.000" }], }, ]; export async function seedAssets( householdIds: Map, userIds: Map, ): Promise { const today = todayIstanbul(); let created = 0; for (const x of ITEMS) { const householdId = householdIds.get(x.household)!; const seedRef = `asset:${x.ref}`; if (await AssetModel.exists({ householdId, seedRef })) continue; const by = userIds.get(x.by)!; const hh = String(householdId); const r = await createAsset( by, hh, assetFormSchema.parse({ assetKey: x.assetKey, name: x.name, note: x.note ?? "", isPrivate: x.isPrivate ?? false, }), ); if (!r.ok) throw new Error(`Seed varlığı oluşturulamadı (${x.ref}): ${r.error}`); await AssetModel.updateOne({ _id: r.data.id }, { $set: { seedRef } }); for (const [i, m] of x.movements.entries()) { const account = m.account ? String((await AccountModel.findOne({ householdId, name: m.account }).lean())!._id) : ""; const res = await addMovement( by, hh, r.data.id, movementFormSchema.parse({ kind: m.kind, date: addDays(today, -m.daysAgo), quantity: m.quantity, amount: m.amount ?? "", accountId: account, storage: m.storage ?? "", note: m.note ?? "", }), ); if (!res.ok) throw new Error(`Seed varlık hareketi eklenemedi (${x.ref}): ${res.error}`); const ref = `${seedRef}:${i}`; const mv = await AssetMovementModel.findOneAndUpdate( { _id: res.data.id }, { $set: { seedRef: ref } }, ).lean(); if (mv?.transactionId) await TransactionModel.updateOne({ _id: mv.transactionId }, { $set: { seedRef: ref } }); } created++; } return created; }