feat(seed): örnek cariler ve hareketleri

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-05 11:58:37 +03:00
parent b6c6be5c97
commit 5648eafd7c
3 changed files with 165 additions and 0 deletions
+158
View File
@@ -0,0 +1,158 @@
import type { Types } from "mongoose";
import { createContact, createContactEntry } from "@/features/contacts/service";
import { AccountModel } from "@/models/account";
import { ContactModel } from "@/models/contact";
import type { ContactEntryKind, ContactRelation } from "@/shared/contacts";
import { todayIstanbul } from "@/shared/dates";
import { formatMoneyInput } from "@/shared/money";
import { addDays } from "@/shared/recurrence";
import { contactEntrySchema, contactFormSchema } from "@/shared/schemas/contact";
/**
* Örnek cariler (Faz 8a): vadesi yaklaşan alacak, kısmen ödenen borç, vadesi geçmiş küçük alacak
* ve "yalnızca ben" cari. İdempotent: cari `seedRef` ile; hareketler yalnızca cari ilk
* oluşturulduğunda eklenir.
*/
type SeedContact = {
ref: string;
household: string;
by: string;
name: string;
relation: ContactRelation;
phone?: string;
isPrivate?: boolean;
dueInDays?: number;
reminderDays?: number;
entries: {
kind: ContactEntryKind;
account: string;
amountMinor: number;
daysAgo: number;
description?: string;
}[];
};
const CONTACTS: SeedContact[] = [
{
ref: "ahmet",
household: "Çakır Ailesi",
by: "admin",
name: "Ahmet Yılmaz",
relation: "friend",
phone: "0532 000 00 01",
dueInDays: 5,
reminderDays: 7,
entries: [
{
kind: "lend",
account: "Ziraat Maaş",
amountMinor: 5_000_00,
daysAgo: 70,
description: "Araba tamiri için",
},
{ kind: "collect", account: "Cüzdan", amountMinor: 2_000_00, daysAgo: 30 },
],
},
{
ref: "hasan",
household: "Çakır Ailesi",
by: "admin",
name: "Hasan Çakır",
relation: "family",
dueInDays: 60,
entries: [
{
kind: "borrow",
account: "Ziraat Maaş",
amountMinor: 20_000_00,
daysAgo: 120,
description: "Ev eşyası için",
},
{ kind: "repay", account: "Ziraat Maaş", amountMinor: 5_000_00, daysAgo: 60 },
{ kind: "repay", account: "Ziraat Maaş", amountMinor: 5_000_00, daysAgo: 10 },
],
},
{
ref: "elif",
household: "Çakır Ailesi",
by: "ayse",
name: "Elif (komşu)",
relation: "neighbor",
dueInDays: -2,
entries: [
{
kind: "lend",
account: "Cüzdan",
amountMinor: 300_00,
daysAgo: 12,
description: "Pazar alışverişi",
},
],
},
{
ref: "selin",
household: "Çakır Ailesi",
by: "ayse",
name: "Selin (iş arkadaşı)",
relation: "work",
isPrivate: true,
entries: [{ kind: "lend", account: "Cüzdan", amountMinor: 1_000_00, daysAgo: 8 }],
},
{
ref: "ali",
household: "Annemler",
by: "fatma",
name: "Ali Demir",
relation: "family",
dueInDays: 45,
entries: [{ kind: "borrow", account: "Vakıfbank Emekli", amountMinor: 3_000_00, daysAgo: 25 }],
},
];
export async function seedContacts(
householdIds: Map<string, Types.ObjectId>,
userIds: Map<string, string>,
): Promise<number> {
const today = todayIstanbul();
let created = 0;
for (const c of CONTACTS) {
const householdId = householdIds.get(c.household)!;
const seedRef = `contact:${c.ref}`;
if (await ContactModel.exists({ householdId, seedRef })) continue;
const by = userIds.get(c.by)!;
const oldest = Math.max(...c.entries.map((e) => e.daysAgo));
const r = await createContact(
by,
String(householdId),
contactFormSchema.parse({
name: c.name,
relation: c.relation,
phone: c.phone ?? "",
openingDate: addDays(today, -oldest - 1),
isPrivate: c.isPrivate ?? false,
dueDate: c.dueInDays !== undefined ? addDays(today, c.dueInDays) : null,
reminderDays: c.reminderDays ?? 3,
}),
);
if (!r.ok) throw new Error(`Seed carisi oluşturulamadı (${c.name}): ${r.error}`);
await ContactModel.updateOne({ _id: r.data.id }, { $set: { seedRef } });
for (const e of c.entries) {
const account = await AccountModel.findOne({ householdId, name: e.account }).lean();
const x = await createContactEntry(
by,
String(householdId),
r.data.id,
contactEntrySchema.parse({
kind: e.kind,
accountId: String(account!._id),
amount: formatMoneyInput(e.amountMinor),
date: addDays(today, -e.daysAgo),
description: e.description ?? "",
}),
);
if (!x.ok) throw new Error(`Seed cari hareketi oluşturulamadı (${c.name}): ${x.error}`);
}
created++;
}
return created;
}