feat(contacts): cari kişiler, hesap ↔ cari transferleri, cari ekstresi ve vade uyarısı, 007 migration

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-05 11:58:37 +03:00
parent dfb83d6fd4
commit 5d370a062e
18 changed files with 1060 additions and 26 deletions
+6 -1
View File
@@ -1,4 +1,5 @@
import { model, models, Schema, type InferSchemaType, type Model } from "mongoose";
import { CONTACT_ENTRY_KINDS } from "@/shared/contacts";
import { TRANSACTION_STATUSES, TRANSACTION_TYPES } from "@/shared/transactions";
/**
@@ -21,7 +22,8 @@ const transactionSchema = new Schema(
status: { type: String, enum: TRANSACTION_STATUSES, default: "posted" },
/** İstanbul gününün başlangıç anı (UTC). */
date: { type: Date, required: true },
accountId: { type: Schema.Types.ObjectId, required: true },
/** Kaynak hesap. Cariden girişte (borç alma, tahsilat) null; hedef `toAccountId`. */
accountId: { type: Schema.Types.ObjectId, default: null },
toAccountId: { type: Schema.Types.ObjectId, default: null },
amountMinor: { type: Number, required: true, min: 1 },
/** Bölünmemiş gelir/giderde kategori; bölünmüşte null ve kalemler `splits`te. */
@@ -53,7 +55,9 @@ const transactionSchema = new Schema(
default: null,
},
statementId: { type: Schema.Types.ObjectId, default: null },
/** Cari transferi: karşı taraf kişi (hesabın biri boş). */
contactId: { type: Schema.Types.ObjectId, default: null },
contactKind: { type: String, enum: [...CONTACT_ENTRY_KINDS, null], default: null },
/**
* Mutabakatı yapılmış hesaplar (Bölüm 6.1). Transfer iki hesaba dokunduğu için hesap bazında
* tutulur. Tutar, tarih, tür veya hesap değişirse işaret kalkar.
@@ -76,6 +80,7 @@ transactionSchema.index({ householdId: 1, accountId: 1, date: -1 });
transactionSchema.index({ householdId: 1, toAccountId: 1, date: -1 });
transactionSchema.index({ householdId: 1, effectiveCategoryIds: 1, date: -1 });
transactionSchema.index({ householdId: 1, tags: 1 });
transactionSchema.index({ householdId: 1, contactId: 1, date: 1 }, { sparse: true });
transactionSchema.index({ "installment.planId": 1 }, { sparse: true });
transactionSchema.index(
{ recurringRuleId: 1, occurrenceIndex: 1 },