feat(seed): örnek cariler ve hareketleri
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user