b8306b3b5d
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
163 lines
4.6 KiB
TypeScript
163 lines
4.6 KiB
TypeScript
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<string, Types.ObjectId>,
|
||
userIds: Map<string, string>,
|
||
): Promise<number> {
|
||
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;
|
||
}
|